diff --git a/domaintools/api.py b/domaintools/api.py index 51acd5c..8a00f01 100644 --- a/domaintools/api.py +++ b/domaintools/api.py @@ -5,6 +5,7 @@ import re import ssl +import yaml from domaintools.constants import ( Endpoint, @@ -12,6 +13,7 @@ ENDPOINT_TO_SOURCE_MAP, RTTF_PRODUCTS_LIST, RTTF_PRODUCTS_CMD_MAPPING, + SPECS_MAPPING, ) from domaintools._version import current as version from domaintools.results import ( @@ -22,6 +24,7 @@ Results, FeedsResults, ) +from domaintools.decorators import api_endpoint, auto_patch_docstrings from domaintools.filters import ( filter_by_riskscore, filter_by_expire_date, @@ -40,6 +43,7 @@ def delimited(items, character="|"): return character.join(items) if type(items) in (list, tuple, set) else items +@auto_patch_docstrings class API(object): """Enables interacting with the DomainTools API via Python: @@ -94,8 +98,10 @@ def __init__( self.key_sign_hash = key_sign_hash self.default_parameters["app_name"] = app_name self.default_parameters["app_version"] = app_version + self.specs = {} self._build_api_url(api_url, api_port) + self._initialize_specs() if not https: raise Exception( @@ -104,8 +110,25 @@ def __init__( if proxy_url and not isinstance(proxy_url, str): raise Exception("Proxy URL must be a string. For example: '127.0.0.1:8888'") + def _initialize_specs(self): + for spec_name, file_path in SPECS_MAPPING.items(): + try: + with open(file_path, "r", encoding="utf-8") as f: + spec_content = yaml.safe_load(f) + if not spec_content: + raise ValueError("Spec file is empty or invalid.") + + self.specs[spec_name] = spec_content + + except Exception as e: + print(f"Error loading {file_path}: {e}") + def _get_ssl_default_context(self, verify_ssl: Union[str, bool]): - return ssl.create_default_context(cafile=verify_ssl) if isinstance(verify_ssl, str) else verify_ssl + return ( + ssl.create_default_context(cafile=verify_ssl) + if isinstance(verify_ssl, str) + else verify_ssl + ) def _build_api_url(self, api_url=None, api_port=None): """Build the API url based on the given url and port. Defaults to `https://api.domaintools.com`""" @@ -133,11 +156,18 @@ def _rate_limit(self, product): hours = limit_hours and 3600 / float(limit_hours) minutes = limit_minutes and 60 / float(limit_minutes) - self.limits[product["id"]] = {"interval": timedelta(seconds=minutes or hours or default)} + self.limits[product["id"]] = { + "interval": timedelta(seconds=minutes or hours or default) + } def _results(self, product, path, cls=Results, **kwargs): """Returns _results for the specified API path with the specified **kwargs parameters""" - if product != "account-information" and self.rate_limit and not self.limits_set and not self.limits: + if ( + product != "account-information" + and self.rate_limit + and not self.limits_set + and not self.limits + ): always_sign_api_key_previous_value = self.always_sign_api_key header_authentication_previous_value = self.header_authentication self._rate_limit(product) @@ -181,7 +211,9 @@ def handle_api_key(self, is_rttf_product, path, parameters): else: raise ValueError( "Invalid value '{0}' for 'key_sign_hash'. " - "Values available are {1}".format(self.key_sign_hash, ",".join(AVAILABLE_KEY_SIGN_HASHES)) + "Values available are {1}".format( + self.key_sign_hash, ",".join(AVAILABLE_KEY_SIGN_HASHES) + ) ) parameters["timestamp"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") @@ -193,7 +225,9 @@ def handle_api_key(self, is_rttf_product, path, parameters): def account_information(self, **kwargs): """Provides a snapshot of your accounts current API usage""" - return self._results("account-information", "/v1/account", items_path=("products",), **kwargs) + return self._results( + "account-information", "/v1/account", items_path=("products",), **kwargs + ) def available_api_calls(self): """Provides a list of api calls that you can use based on your account information.""" @@ -396,7 +430,9 @@ def reputation(self, query, include_reasons=False, **kwargs): def reverse_ip(self, domain=None, limit=None, **kwargs): """Pass in a domain name.""" - return self._results("reverse-ip", "/v1/{0}/reverse-ip".format(domain), limit=limit, **kwargs) + return self._results( + "reverse-ip", "/v1/{0}/reverse-ip".format(domain), limit=limit, **kwargs + ) def host_domains(self, ip=None, limit=None, **kwargs): """Pass in an IP address.""" @@ -570,8 +606,12 @@ def iris_enrich(self, *domains, **kwargs): younger_than_date = kwargs.pop("younger_than_date", {}) or None older_than_date = kwargs.pop("older_than_date", {}) or None updated_after = kwargs.pop("updated_after", {}) or None - include_domains_with_missing_field = kwargs.pop("include_domains_with_missing_field", {}) or None - exclude_domains_with_missing_field = kwargs.pop("exclude_domains_with_missing_field", {}) or None + include_domains_with_missing_field = ( + kwargs.pop("include_domains_with_missing_field", {}) or None + ) + exclude_domains_with_missing_field = ( + kwargs.pop("exclude_domains_with_missing_field", {}) or None + ) filtered_results = DTResultFilter(result_set=results).by( [ @@ -624,6 +664,7 @@ def iris_enrich_cli(self, domains=None, **kwargs): **kwargs, ) + @api_endpoint(spec_name="iris", path="/v1/iris-investigate/", methods="post") def iris_investigate( self, domains=None, @@ -641,29 +682,6 @@ def iris_investigate( **kwargs, ): """Returns back a list of domains based on the provided filters. - The following filters are available beyond what is parameterized as kwargs: - - - ip: Search for domains having this IP. - - email: Search for domains with this email in their data. - - email_domain: Search for domains where the email address uses this domain. - - nameserver_host: Search for domains with this nameserver. - - nameserver_domain: Search for domains with a nameserver that has this domain. - - nameserver_ip: Search for domains with a nameserver on this IP. - - registrar: Search for domains with this registrar. - - registrant: Search for domains with this registrant name. - - registrant_org: Search for domains with this registrant organization. - - mailserver_host: Search for domains with this mailserver. - - mailserver_domain: Search for domains with a mailserver that has this domain. - - mailserver_ip: Search for domains with a mailserver on this IP. - - redirect_domain: Search for domains which redirect to this domain. - - ssl_hash: Search for domains which have an SSL certificate with this hash. - - ssl_subject: Search for domains which have an SSL certificate with this subject string. - - ssl_email: Search for domains which have an SSL certificate with this email in it. - - ssl_org: Search for domains which have an SSL certificate with this organization in it. - - google_analytics: Search for domains which have this Google Analytics code. - - adsense: Search for domains which have this AdSense code. - - tld: Filter by TLD. Must be combined with another parameter. - - search_hash: Use search hash from Iris to bring back domains. You can loop over results of your investigation as if it was a native Python list: diff --git a/domaintools/base_results.py b/domaintools/base_results.py index 35a6479..29c6704 100644 --- a/domaintools/base_results.py +++ b/domaintools/base_results.py @@ -94,8 +94,7 @@ def _get_session_params_and_headers(self): headers["accept"] = HEADER_ACCEPT_KEY_CSV_FORMAT if self.api.header_authentication: - header_key_for_api_key = "X-Api-Key" if is_rttf_product else "X-API-Key" - headers[header_key_for_api_key] = self.api.key + headers["X-Api-Key"] = self.api.key session_param_and_headers = {"parameters": parameters, "headers": headers} return session_param_and_headers @@ -342,7 +341,9 @@ def html(self): ) def as_list(self): - return "\n".join([json.dumps(item, indent=4, separators=(",", ": ")) for item in self._items()]) + return "\n".join( + [json.dumps(item, indent=4, separators=(",", ": ")) for item in self._items()] + ) def __str__(self): return str( diff --git a/domaintools/constants.py b/domaintools/constants.py index d1dc8b7..b000a26 100644 --- a/domaintools/constants.py +++ b/domaintools/constants.py @@ -56,3 +56,8 @@ class OutputFormat(Enum): "real-time-domain-discovery-feed-(api)": "domaindiscovery", "real-time-domain-discovery-feed-(s3)": "domaindiscovery", } + +SPECS_MAPPING = { + "iris": "domaintools/specs/iris-openapi.yaml", + # "rttf": "domaintools/specs/feeds-openapi.yaml", +} diff --git a/domaintools/decorators.py b/domaintools/decorators.py new file mode 100644 index 0000000..4640a8e --- /dev/null +++ b/domaintools/decorators.py @@ -0,0 +1,57 @@ +import functools + +from typing import List, Union + +from domaintools.docstring_patcher import DocstringPatcher + + +def api_endpoint(spec_name: str, path: str, methods: Union[str, List[str]]): + """ + Decorator to tag a method as an API endpoint. + + Args: + spec_name: The key for the spec in api_instance.specs + path: The API path (e.g., "/users") + methods: A single method ("get") or list of methods (["get", "post"]) + that this function handles. + """ + + def decorator(func): + func._api_spec_name = spec_name + func._api_path = path + + # Always store the methods as a list + if isinstance(methods, str): + func._api_methods = [methods] + else: + func._api_methods = methods + + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + return func(*args, **kwargs) + + # Copy all tags to the wrapper + wrapper._api_spec_name = func._api_spec_name + wrapper._api_path = func._api_path + wrapper._api_methods = func._api_methods + return wrapper + + return decorator + + +def auto_patch_docstrings(cls): + original_init = cls.__init__ + + @functools.wraps(original_init) + def new_init(self, *args, **kwargs): + original_init(self, *args, **kwargs) + try: + # We instantiate our patcher and run it + patcher = DocstringPatcher() + patcher.patch(self) + except Exception as e: + print(f"Auto-patching failed: {e}") + + cls.__init__ = new_init + + return cls diff --git a/domaintools/docstring_patcher.py b/domaintools/docstring_patcher.py new file mode 100644 index 0000000..45f4f54 --- /dev/null +++ b/domaintools/docstring_patcher.py @@ -0,0 +1,334 @@ +import inspect +import functools +import textwrap +import logging + + +class DocstringPatcher: + """ + Patches docstrings for methods decorated with @api_endpoint. + - Uses the 'methods' list provided by the decorator. + - Finds non-standard parameters inside the 'requestBody' object. + - Displays Query Params, Request Body, and Result Body (Responses) + for all operations. + - Unpacks and displays properties of request body schemas. + - Searches components.parameters for request body properties + that match by name. + """ + + def patch(self, api_instance): + method_names = [] + for attr_name in dir(api_instance): + attr = getattr(api_instance, attr_name) + if ( + inspect.ismethod(attr) + and hasattr(attr, "_api_spec_name") + and hasattr(attr, "_api_path") + and hasattr(attr, "_api_methods") + ): + method_names.append(attr_name) + + for attr_name in method_names: + original_method = getattr(api_instance, attr_name) + original_function = original_method.__func__ + + spec_name = getattr(original_function, "_api_spec_name", None) + path = getattr(original_function, "_api_path", None) + http_methods_to_check = getattr(original_function, "_api_methods", []) + + spec_to_use = api_instance.specs.get(spec_name) + original_doc = inspect.getdoc(original_function) or "" + + all_doc_sections = [] + if spec_to_use: + path_item = spec_to_use.get("paths", {}).get(path, {}) + for http_method in http_methods_to_check: + if http_method.lower() in path_item: + api_doc = self._generate_api_doc_string(spec_to_use, path, http_method) + all_doc_sections.append(api_doc) + + if not all_doc_sections: + all_doc_sections.append( + f"\n--- API Details Error ---" + f"\n (Could not find operations {http_methods_to_check} for path '{path}' in spec '{spec_name}')" + ) + + new_doc = textwrap.dedent(original_doc) + "\n\n" + "\n\n".join(all_doc_sections) + + @functools.wraps(original_function) + def method_wrapper(*args, _orig_meth=original_method, **kwargs): + return _orig_meth(*args, **kwargs) + + method_wrapper.__doc__ = new_doc + setattr( + api_instance, + attr_name, + method_wrapper.__get__(api_instance, api_instance.__class__), + ) + + def _generate_api_doc_string(self, spec: dict, path: str, method: str) -> str: + """Creates the formatted API docstring section for ONE operation.""" + + details = self._get_operation_details(spec, path, method) + lines = [f"--- Operation: {method.upper()} {path} ---"] + + lines.append(f"\n Summary: {details.get('summary', 'N/A')}") + lines.append(f" Description: {details.get('description', 'N/A')}") + lines.append(f" External Doc: {details.get('external_doc', 'N/A')}") + + # 1. Always display Query Parameters + lines.append("\n Query Parameters:") + if not details["query_params"]: + lines.append(" (No query parameters)") + else: + for param in details["query_params"]: + lines.append(f"\n **{param['name']}** ({param['type']})") + lines.append(f" Required: {param['required']}") + lines.append(f" Description: {param['description']}") + + # 2. Always display Request Body + lines.append("\n Request Body:") + if not details["request_body"]: + lines.append(" (No request body)") + else: + body = details["request_body"] + lines.append(f"\n **{body['type']}**") + lines.append(f" Required: {body['required']}") + lines.append(f" Description: {body['description']}") + + if body.get("properties"): + lines.append(f" Properties:") + for prop in body["properties"]: + lines.append(f"\n **{prop['name']}** ({prop['type']})") + lines.append(f" Description: {prop['description']}") + + if body.get("parameters"): + lines.append(f" Parameters (associated with this body):") + for param in body["parameters"]: + param_in = param.get("in", "N/A") + lines.append( + f"\n **{param['name']}** ({param['type']}) [in: {param_in}]" + ) + lines.append(f" Required: {param['required']}") + lines.append(f" Description: {param['description']}") + + # 3. Always display Result Body (Responses) + lines.append("\n Result Body (Responses):") + if not details["responses"]: + lines.append(" (No responses defined in spec)") + else: + for resp in details["responses"]: + lines.append(f"\n **{resp['status_code']}**: ({resp['type']})") + lines.append(f" Description: {resp['description']}") + + return "\n".join(lines) + + def _get_operation_details(self, spec: dict, path: str, method: str) -> dict: + """ + Gets all details. Includes: + - Logic to find non-standard 'parameters' in 'requestBody' + - Logic to parse requestBody schema properties + - Logic to parse responses + - **NEW**: Logic to match requestBody properties to components/parameters + """ + details = {"query_params": [], "request_body": None, "responses": []} + if not spec: + return details + + try: + # --- Get component parameters for lookup --- + components = spec.get("components", {}) + all_component_params = components.get("parameters", {}) + + path_item = spec.get("paths", {}).get(path, {}) + operation = path_item.get(method.lower(), {}) + if not operation: + return details + + # --- Parameter Logic --- + path_level_params = path_item.get("parameters", []) + operation_level_params = operation.get("parameters", []) + body_level_params = [] + + body_def = operation.get("requestBody") + resolved_body_def = {} + if body_def: + if "$ref" in body_def: + resolved_body_def = self._resolve_ref(spec, body_def["$ref"]) + else: + resolved_body_def = body_def + body_level_params = resolved_body_def.get("parameters", []) + + all_param_defs = path_level_params + operation_level_params + # --- End Parameter Logic --- + + details["summary"] = operation.get("summary") + details["description"] = operation.get("description") + details["external_doc"] = operation.get("externalDocs", {}).get("url", "N/A") + + # --- Query Param Processing (from path/operation only) --- + resolved_params = [] + for param_def in all_param_defs: + if "$ref" in param_def: + resolved_params.append(self._resolve_ref(spec, param_def["$ref"])) + else: + resolved_params.append(param_def) + + for p in [p for p in resolved_params if p.get("in") == "query"]: + details["query_params"].append( + { + "name": p.get("name"), + "required": p.get("required", False), + "description": p.get("description", "N/A"), + "type": self._get_param_type(spec, p.get("schema")), + } + ) + # --- End Query Param Processing --- + + # --- Request Body Processing --- + if body_def: + content = resolved_body_def.get("content", {}) + media_type = next(iter(content.values()), None) + schema_type = "N/A" + schema = {} + + if media_type and "schema" in media_type: + schema = media_type["schema"] + schema_type = self._get_param_type(spec, schema) + + details["request_body"] = { + "required": resolved_body_def.get("required", False), + "description": resolved_body_def.get("description", "N/A"), + "type": schema_type, + "parameters": [], + "properties": [], + } + + # --- Process schema properties with new lookup logic --- + resolved_schema = {} + if "$ref" in schema: + resolved_schema = self._resolve_ref(spec, schema["$ref"]) + elif schema.get("type") == "object": + resolved_schema = schema + + if resolved_schema.get("type") == "object" and "properties" in resolved_schema: + for prop_name, prop_def in resolved_schema["properties"].items(): + + found_param_match = False + # --- Try to find a match in components/parameters --- + # (Iterate over values, e.g., the LimitParam object) + for component_param_def in all_component_params.values(): + if component_param_def.get("name") == prop_name: + # Found a match! Use its details. + prop_type = self._get_param_type( + spec, component_param_def.get("schema") + ) + prop_desc = component_param_def.get("description", "N/A") + details["request_body"]["properties"].append( + {"name": prop_name, "type": prop_type, "description": prop_desc} + ) + found_param_match = True + break + + if not found_param_match: + # No match, process as a normal schema property + prop_type = self._get_param_type(spec, prop_def) + prop_desc = prop_def.get("description", "N/A") + details["request_body"]["properties"].append( + {"name": prop_name, "type": prop_type, "description": prop_desc} + ) + + # --- Body Parameter Processing (for non-standard spec) --- + resolved_body_params = [] + for param_def in body_level_params: + if "$ref" in param_def: + resolved_body_params.append(self._resolve_ref(spec, param_def["$ref"])) + else: + resolved_body_params.append(param_def) + + for p in resolved_body_params: + details["request_body"]["parameters"].append( + { + "name": p.get("name"), + "in": p.get("in"), + "required": p.get("required", False), + "description": p.get("description", "N/A"), + "type": self._get_param_type(spec, p.get("schema")), + } + ) + # --- End Request Body Processing --- + + # --- Response Processing Logic --- + responses_def = operation.get("responses", {}) + for status_code, resp_def in responses_def.items(): + resolved_resp = {} + if "$ref" in resp_def: + resolved_resp = self._resolve_ref(spec, resp_def["$ref"]) + else: + resolved_resp = resp_def + + description = resolved_resp.get("description", "N/A") + resp_type = "N/A" + content = resolved_resp.get("content", {}) + media_type = next(iter(content.values()), None) + + if media_type and "schema" in media_type: + schema = media_type["schema"] + resp_type = self._get_param_type(spec, schema) + + details["responses"].append( + { + "status_code": status_code, + "description": description, + "type": resp_type, + } + ) + # --- END: Response Processing Logic --- + + return details + except Exception as e: + logging.warning(f"Error parsing spec for {method.upper()} {path}: {e}", exc_info=True) + return details + + def _resolve_ref(self, spec: dict, ref: str): + """Resolves a JSON schema $ref string.""" + if not spec or not ref.startswith("#/"): + return {} + parts = ref.split("/")[1:] + current_obj = spec + for part in parts: + if isinstance(current_obj, list): + try: + current_obj = current_obj[int(part)] + except (IndexError, ValueError): + return {} + elif isinstance(current_obj, dict): + current_obj = current_obj.get(part) + else: + return {} + if current_obj is None: + return {} + return current_obj + + def _get_param_type(self, spec: dict, schema: dict) -> str: + """Gets a display-friendly type name from a schema object.""" + if not schema: + return "N/A" + + # Check for malformed refs (like in your example spec) + schema_ref = schema.get("$ref") + if not schema_ref: + # Handle user's typo: "$ref:" + schema_ref = schema.get("$ref:") + + if schema_ref: + return schema_ref.split("/")[-1] + + schema_type = schema.get("type", "N/A") + + if schema_type == "array": + items_schema = schema.get("items", {}) + items_type = self._get_param_type(spec, items_schema) + return f"array[{items_type}]" + + return schema_type diff --git a/domaintools/specs/iris-openapi.yaml b/domaintools/specs/iris-openapi.yaml new file mode 100644 index 0000000..f2dddb8 --- /dev/null +++ b/domaintools/specs/iris-openapi.yaml @@ -0,0 +1,2741 @@ +openapi: 3.0.3 +info: + title: DomainTools Iris API + version: 1.0.0 + description: | + The OpenAPI spec for DomainTools Iris endpoints. +servers: + - url: https://api.domaintools.com + description: DomainTools APIs +security: + - header_auth: [] + - open_key_auth: [] + - hmac_auth: [] +tags: + - name: Information + description: | + Access the latest information about your account, including service + limits. + - name: Iris Detect + description: | + Iris Detect is an Internet infrastructure detection, monitoring, and enforcement tool. + It rapidly discovers malicious domains that are engaged in brand impersonation, risk-scores them within minutes, and supports your automation of detection, escalation, and enforcement actions. + - name: Iris Enrich + description: | + Designed to support high query volumes with batch processing and fast response times, the Iris Enrich API provides actionable insights-at-scale with enterprise-scale ingestion of DomainTools data + - name: Iris Investigate + description: | + The Iris Investigate API is ideally suited for investigate and orchestrate use cases at human scale. Identify threats, map adversary infrastructure, and streamline investigations. +paths: + /v1/iris-detect/domains/: + patch: + operationId: patchDetectDomains + summary: Add and remove domains from Watchlist or Ignored lists. + tags: + - Iris Detect + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/WatchlistState' + responses: + '200': + $ref: '#/components/responses/DetectWatchlistOk' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + externalDocs: + url: https://docs.domaintools.com/api/iris/detect/reference/#add-remove-from-watchlist + /v1/iris-detect/domains/ignored/: + get: + operationId: getDetectIgnored + summary: Provide ignored domains for active monitors in an account. + tags: + - Iris Detect + parameters: + - $ref: '#/components/parameters/appName' + - $ref: '#/components/parameters/appPartner' + - $ref: '#/components/parameters/appVersion' + - $ref: '#/components/parameters/changedSince' + - $ref: '#/components/parameters/discoveredBefore' + - $ref: '#/components/parameters/discoveredSince' + - $ref: '#/components/parameters/domainState' + - $ref: '#/components/parameters/escalatedSince' + - $ref: '#/components/parameters/includeDomainData' + - $ref: '#/components/parameters/irisContainsSearch' + - $ref: '#/components/parameters/irisResultsLimit' + - $ref: '#/components/parameters/monitorId' + - $ref: '#/components/parameters/mxExists' + - $ref: '#/components/parameters/resultsOffset' + - $ref: '#/components/parameters/order' + - $ref: '#/components/parameters/preview' + - $ref: '#/components/parameters/riskScoreRanges' + - $ref: '#/components/parameters/sortDetect' + - $ref: '#/components/parameters/tlds' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/DetectDomainList' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + externalDocs: + url: https://docs.domaintools.com/api/iris/detect/reference/#domains + /v1/iris-detect/domains/new/: + get: + operationId: getDetectNewDomains + summary: Provide newly discovered domains for active monitors in an account. + tags: + - Iris Detect + parameters: + - $ref: '#/components/parameters/appName' + - $ref: '#/components/parameters/appPartner' + - $ref: '#/components/parameters/appVersion' + - $ref: '#/components/parameters/discoveredBefore' + - $ref: '#/components/parameters/discoveredSince' + - $ref: '#/components/parameters/includeDomainData' + - $ref: '#/components/parameters/irisContainsSearch' + - $ref: '#/components/parameters/irisResultsLimit' + - $ref: '#/components/parameters/monitorId' + - $ref: '#/components/parameters/mxExists' + - $ref: '#/components/parameters/resultsOffset' + - $ref: '#/components/parameters/order' + - $ref: '#/components/parameters/preview' + - $ref: '#/components/parameters/riskScoreRanges' + - $ref: '#/components/parameters/sortDetect' + - $ref: '#/components/parameters/tlds' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/DetectDomainList' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + externalDocs: + url: https://docs.domaintools.com/api/iris/detect/reference/#domains + /v1/iris-detect/domains/watched/: + get: + operationId: getDomainsWatched + summary: Provide recently changed or escalated domains for active monitors in an account. + tags: + - Iris Detect + parameters: + - $ref: '#/components/parameters/appName' + - $ref: '#/components/parameters/appPartner' + - $ref: '#/components/parameters/appVersion' + - $ref: '#/components/parameters/changedSince' + - $ref: '#/components/parameters/discoveredBefore' + - $ref: '#/components/parameters/discoveredSince' + - $ref: '#/components/parameters/escalatedSince' + - $ref: '#/components/parameters/escalationTypes' + - $ref: '#/components/parameters/includeDomainData' + - $ref: '#/components/parameters/irisContainsSearch' + - $ref: '#/components/parameters/irisResultsLimit' + - $ref: '#/components/parameters/monitorId' + - $ref: '#/components/parameters/mxExists' + - $ref: '#/components/parameters/resultsOffset' + - $ref: '#/components/parameters/order' + - $ref: '#/components/parameters/preview' + - $ref: '#/components/parameters/riskScoreRanges' + - $ref: '#/components/parameters/sortDetect' + - $ref: '#/components/parameters/tlds' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/DetectDomainList' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + externalDocs: + url: https://docs.domaintools.com/api/iris/detect/reference/#domains + /v1/iris-detect/escalations/: + post: + operationId: postDetectEscalations + summary: Escalate internally and externally. + tags: + - Iris Detect + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/WatchlistEscalation' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Escalations' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + externalDocs: + url: https://docs.domaintools.com/api/iris/detect/reference/#escalate + /v1/iris-detect/monitors/: + get: + operationId: getDetectMonitors + summary: Retrieves monitors and monitor IDs for an account. + tags: + - Iris Detect + parameters: + - $ref: '#/components/parameters/appName' + - $ref: '#/components/parameters/appPartner' + - $ref: '#/components/parameters/appVersion' + - $ref: '#/components/parameters/datetimeCountsSince' + - $ref: '#/components/parameters/includeCounts' + - $ref: '#/components/parameters/limitMonitors' + - $ref: '#/components/parameters/resultsOffset' + - $ref: '#/components/parameters/order' + - $ref: '#/components/parameters/sortMonitorList' + responses: + '200': + $ref: '#/components/responses/DetectMonitorSuccess' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + externalDocs: + url: https://docs.domaintools.com/api/iris/detect/reference/#monitor-list + /v1/iris-enrich/: + get: + operationId: getIrisEnrich + summary: Returns results from a GET request to Iris Enrich. + tags: + - Iris Enrich + parameters: + - $ref: '#/components/parameters/appName' + - $ref: '#/components/parameters/appPartner' + - $ref: '#/components/parameters/appVersion' + - $ref: '#/components/parameters/domainsQueryRequired' + - $ref: '#/components/parameters/parsedDomainRdapFlag' + - $ref: '#/components/parameters/parsedWhoisFlag' + - $ref: '#/components/parameters/responseFormat' + responses: + '200': + $ref: '#/components/responses/EnrichSuccess' + '206': + $ref: '#/components/responses/IrisPartialContent' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + '503': + $ref: '#/components/responses/ServiceUnavailable' + externalDocs: + url: https://docs.domaintools.com/api/iris/enrich/ + post: + operationId: postIrisEnrich + summary: Returns results from a POST request to Iris Enrich. + tags: + - Iris Enrich + requestBody: + $ref: '#/components/requestBodies/Enrich' + responses: + '200': + $ref: '#/components/responses/EnrichSuccess' + '206': + $ref: '#/components/responses/IrisPartialContent' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + '503': + $ref: '#/components/responses/ServiceUnavailable' + externalDocs: + url: https://docs.domaintools.com/api/iris/enrich/ + /v1/iris-investigate/: + get: + operationId: getIrisInvestigate + summary: | + Returns data from a GET request. + Parameters are identified in descriptions as either base or filter. + Search with base parameters and filter down base results with filter parameters. + tags: + - Iris Investigate + description: | + Consider using POST for complex requests. + parameters: + - $ref: '#/components/parameters/adsense' + - $ref: '#/components/parameters/baiduCode' + - $ref: '#/components/parameters/contactName' + - $ref: '#/components/parameters/contactPhone' + - $ref: '#/components/parameters/contactStreet' + - $ref: '#/components/parameters/domainLastIp' + - $ref: '#/components/parameters/domainsQuery' + - $ref: '#/components/parameters/emailAny' + - $ref: '#/components/parameters/emailDnsSoa' + - $ref: '#/components/parameters/emailDomain' + - $ref: '#/components/parameters/emailHistoricalWhois' + - $ref: '#/components/parameters/facebookCode' + - $ref: '#/components/parameters/googleAnalytics4Code' + - $ref: '#/components/parameters/googleAnalyticsCode' + - $ref: '#/components/parameters/googleTagManagerCode' + - $ref: '#/components/parameters/hotJarCode' + - $ref: '#/components/parameters/ianaId' + - $ref: '#/components/parameters/mailserverDomain' + - $ref: '#/components/parameters/mailserverHost' + - $ref: '#/components/parameters/mailserverIp' + - $ref: '#/components/parameters/matomoCode' + - $ref: '#/components/parameters/nameserverDomain' + - $ref: '#/components/parameters/nameserverHost' + - $ref: '#/components/parameters/nameserverIp' + - $ref: '#/components/parameters/redirectDomain' + - $ref: '#/components/parameters/registrant' + - $ref: '#/components/parameters/registrantHistoricalWhois' + - $ref: '#/components/parameters/registrantOrg' + - $ref: '#/components/parameters/registrar' + - $ref: '#/components/parameters/searchHash' + - $ref: '#/components/parameters/serverType' + - $ref: '#/components/parameters/sslAltNames' + - $ref: '#/components/parameters/sslCommonName' + - $ref: '#/components/parameters/sslDuration' + - $ref: '#/components/parameters/sslEmail' + - $ref: '#/components/parameters/sslHash' + - $ref: '#/components/parameters/sslOrg' + - $ref: '#/components/parameters/sslSubject' + - $ref: '#/components/parameters/statCounterProjectCode' + - $ref: '#/components/parameters/statCounterSecurityCode' + - $ref: '#/components/parameters/taggedWithAll' + - $ref: '#/components/parameters/taggedWithAny' + - $ref: '#/components/parameters/websiteTitle' + - $ref: '#/components/parameters/whoisFreeText' + - $ref: '#/components/parameters/whoisHistoricalFreeText' + - $ref: '#/components/parameters/yandexCode' + - $ref: '#/components/parameters/active' + - $ref: '#/components/parameters/createDate' + - $ref: '#/components/parameters/createDateWithin' + - $ref: '#/components/parameters/expirationDate' + - $ref: '#/components/parameters/firstSeenSince' + - $ref: '#/components/parameters/firstSeenWithin' + - $ref: '#/components/parameters/notTaggedWithAll' + - $ref: '#/components/parameters/notTaggedWithAny' + - $ref: '#/components/parameters/topLevelDomain' + - $ref: '#/components/parameters/parsedDomainRdapFlag' + - $ref: '#/components/parameters/parsedWhoisFlag' + - $ref: '#/components/parameters/nextPageUrl' + - $ref: '#/components/parameters/responseFormat' + - $ref: '#/components/parameters/resultsPageSize' + - $ref: '#/components/parameters/resultsPosition' + - $ref: '#/components/parameters/resultsSortBy' + - $ref: '#/components/parameters/resultsSortDirection' + - $ref: '#/components/parameters/appName' + - $ref: '#/components/parameters/appPartner' + - $ref: '#/components/parameters/appVersion' + responses: + '200': + $ref: '#/components/responses/InvestigateSuccess' + '206': + $ref: '#/components/responses/IrisPartialContent' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + '503': + $ref: '#/components/responses/ServiceUnavailable' + externalDocs: + url: https://docs.domaintools.com/api/iris/investigate/ + post: + operationId: postIrisInvestigate + summary: Returns data from a POST request. + tags: + - Iris Investigate + description: The GET method is available for simple queries. + requestBody: + $ref: '#/components/requestBodies/Investigate' + responses: + '200': + $ref: '#/components/responses/InvestigateSuccess' + '206': + $ref: '#/components/responses/IrisPartialContent' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + '503': + $ref: '#/components/responses/ServiceUnavailable' + externalDocs: + url: https://docs.domaintools.com/api/iris/investigate/ + /v1/account/: + get: + operationId: getAccountInfo + summary: Account Information + description: Information of the active API endpoints, rate limits and usage for an account. + tags: + - Information + parameters: + - $ref: '#/components/parameters/appPartner' + - $ref: '#/components/parameters/appName' + - $ref: '#/components/parameters/appVersion' + - $ref: '#/components/parameters/responseFormat' + responses: + '200': + $ref: '#/components/responses/AccountSuccess' + externalDocs: + url: https://docs.domaintools.com/api/general/account_information/ +components: + parameters: + appName: + name: app_name + in: query + description: | + Appliance, module, or playbook, or any combination of these. + schema: + $ref: '#/components/schemas/IdentifierString' + appPartner: + name: app_partner + in: query + description: | + Your product name. + schema: + $ref: '#/components/schemas/IdentifierString' + appVersion: + name: app_version + in: query + description: | + Version of your integration/connector. + schema: + $ref: '#/components/schemas/IdentifierString' + parsedDomainRdapFlag: + name: parsed_domain_rdap + in: query + description: | + Flag. + If set to `true`, includes the full parsed Domain RDAP record in the response. + schema: + $ref: '#/components/schemas/BooleanOptInFlag' + parsedWhoisFlag: + name: parsed_whois + in: query + description: | + Flag. + If set to 'true', includes the full parsed WHOIS record in the response. + schema: + $ref: '#/components/schemas/BooleanOptInFlag' + responseFormat: + name: format + in: query + description: | + Specifies the desired response format. + schema: + $ref: '#/components/schemas/ResponseFormat' + resultsPageSize: + name: page_size + in: query + description: | + Adjusts the number of results returned per page. + The default is 500. Use this parameter to request a smaller page size. + schema: + type: integer + minimum: 1 + maximum: 500 + offset: + $ref: '#/components/parameters/resultsOffset' + active: + in: query + name: active + description: | + Search filter parameter. + Set to `true` to only return domains that have either an entry in the global Domain Name System, OR are listed as registered by the registry. + Set to `false` to only return domains that do not have an entry in the global DNS, AND are not listed as registered by the registry. + schema: + type: boolean + adsense: + in: query + name: adsense + description: | + Base search parameter. Domains with a Google AdSense tracking code. + schema: + $ref: '#/components/schemas/IdentifierString' + baiduCode: + in: query + name: baidu_analytics + description: | + Base search parameter. Baidu Analytics code. + schema: + $ref: '#/components/schemas/IdentifierString' + changedSince: + in: query + name: changed_since + description: | + Most relevant for the `/watched` endpoint to control the timeframe for changes to DNS or WHOIS fields for watched domains. + schema: + $ref: '#/components/schemas/TimestampFilter' + contactName: + in: query + name: contact_name + description: | + Base search parameter. + Contact name from domain registration data. + Supports WHOIS/RDAP Fields Search. + schema: + $ref: '#/components/schemas/GenericString' + contactPhone: + in: query + name: contact_phone + description: | + Base search parameter. + Contact phone number from domain registration data. + Supports WHOIS/RDAP Fields Search. + schema: + $ref: '#/components/schemas/GenericString' + contactStreet: + in: query + name: contact_street + description: | + Base search parameter. + Contact street address from domain registration data. + Supports WHOIS/RDAP Fields Search. + schema: + $ref: '#/components/schemas/GenericString' + createDate: + in: query + name: create_date + description: | + Search filter parameter. + Filters domains based on the `create_date` field. + Supports [`>`, `>=`, `<`, `<=`] operators, or no operator for exact matches. + schema: + $ref: '#/components/schemas/DateOperatorsFilter' + createDateWithin: + in: query + name: create_date_within + description: | + Search filter parameter. + Filter domains based on the `create_date` field: the maximum number of days since a domain was first discovered. + schema: + $ref: '#/components/schemas/MaxDaysSince' + datetimeCountsSince: + in: query + name: datetime_counts_since + description: | + Filters counts to include only those generated since the specified ISO-8601 date-time. + This parameter is conditionally required if `include_counts` is set to `true`. + Example: `2022-02-10T00:00:00Z` + schema: + $ref: '#/components/schemas/TimestampFilter' + discoveredBefore: + in: query + name: discovered_before + description: | + Most relevant for the /new endpoint to control the timeframe for when a new domain was discovered. Returns domains discovered before provided date/time. Use with `discovered_since` to return domains discovered in a specific time window. + Example: `2022-02-10T00:00:00Z (ISO-8601)` + schema: + $ref: '#/components/schemas/TimestampFilter' + discoveredSince: + in: query + name: discovered_since + description: | + Most relevant for the /new endpoint to control the timeframe for when a new domain was discovered. + Example: `2022-02-10T00:00:00Z (ISO-8601)` + schema: + $ref: '#/components/schemas/TimestampFilter' + domainsQuery: + in: query + name: domain + description: | + Base search parameter. + One or more domains (comma-separated) to be investigated. + Example: `example.com,domaintools.com`. + schema: + $ref: '#/components/schemas/ApexDomainList' + domainsQueryRequired: + in: query + name: domain + description: | + Required. One or more domains (comma-separated) to be investigated. + Example: `example.com,domaintools.com` + required: true + schema: + $ref: '#/components/schemas/ApexDomainList' + domainState: + in: query + name: domain_state + description: | + Filters domains based on their state. + schema: + type: string + enum: + - active + - inactive + domainLastIp: + in: query + name: ip + description: | + Base search parameter. + IPv4 address the registered domain was last known to point to during an active DNS check. + required: false + schema: + $ref: '#/components/schemas/IPv4Address' + emailAny: + in: query + name: email + description: | + Base search parameter. + Email address from the most recently available WHOIS record, DNS SOA record or SSL certificate. + schema: + $ref: '#/components/schemas/EmailAddress' + emailDnsSoa: + in: query + name: email_dns_soa + description: | + Base search parameter. DNS SOA email. + schema: + $ref: '#/components/schemas/EmailAddress' + emailDomain: + in: query + name: email_domain + description: Only the domain portion of a WHOIS or DNS SOA email address. + schema: + $ref: '#/components/schemas/ApexDomain' + emailHistoricalWhois: + in: query + name: historical_free_text + description: Free text search of a domain's historical WHOIS records. + schema: + $ref: '#/components/schemas/GenericString' + escalatedSince: + in: query + name: escalated_since + description: 'Most relevant for the /watched endpoint to control the timeframe for when a domain was most recently escalated. Example: 2022-02-10T00:00:00Z (ISO-8601)' + schema: + $ref: '#/components/schemas/TimestampFilter' + escalationTypes: + in: query + name: escalation_types + description: Filters domains based on specific escalation types. Multiple types can be provided. + style: form + explode: true + schema: + $ref: '#/components/schemas/EscalationTypeEnum' + expirationDate: + in: query + name: expiration_date + description: | + Search filter parameter. + Only include domains expiring on a specific date. + schema: + $ref: '#/components/schemas/DateFilter' + facebookCode: + in: query + name: facebook + description: | + Facebook/Meta tracking code. + schema: + $ref: '#/components/schemas/IdentifierString' + firstSeenSince: + in: query + name: first_seen_since + description: | + Search filter parameter. + Filter domains based on the `first_seen` timestamp. + Returns domains whose `current_lifecycle_first_seen` value is *after* the given datetime. + schema: + $ref: '#/components/schemas/TimestampFilter' + firstSeenWithin: + in: query + name: first_seen_within + description: | + Search filter parameter. + Filter domains based on the `first_seen` field. + Returns only those domains first discovered within the last N seconds. + schema: + $ref: '#/components/schemas/TimeWindowSeconds' + googleAnalyticsCode: + in: query + name: google_analytics + description: | + Base search parameter. + Domains with a Google Analytics tracking code. + schema: + $ref: '#/components/schemas/IdentifierString' + googleAnalytics4Code: + in: query + name: google_analytics_4 + description: | + Base search parameter. + Domains with a Google Analytics tracking code. + schema: + $ref: '#/components/schemas/IdentifierString' + googleTagManagerCode: + in: query + name: google_tag_manager + description: | + Base search parameter. + Google Tag Manager tracking code. + schema: + $ref: '#/components/schemas/IdentifierString' + hotJarCode: + in: query + name: hotjar + description: | + Base search parameter. + Hotjar tracking code. + schema: + $ref: '#/components/schemas/IdentifierString' + ianaId: + in: query + name: iana_id + description: | + Base search parameter. + Registrar IANA code from most recent RDAP record for a domain. + schema: + $ref: '#/components/schemas/IdentifierString' + includeCounts: + in: query + name: include_counts + description: | + If set to `true`, the response will include counts for new, watched, changed, and escalated domains for each monitor. + schema: + $ref: '#/components/schemas/BooleanOptInFlag' + includeDomainData: + in: query + name: include_domain_data + description: | + If set to true, includes additional DNS and WHOIS details in the response. + schema: + $ref: '#/components/schemas/BooleanOptInFlag' + irisResultsLimit: + in: query + name: limit + description: | + Specify the maximum number of records to retrieve in an API query. + The maximum value is **100**, but this is reduced to **50** if `include_domain_data=true`. + schema: + type: integer + maximum: 100 + minimum: 1 + limitMonitors: + in: query + name: limit + description: | + Specifies the maximum number of monitors to retrieve. + The maximum value is 100, but this may be further restricted if `include_counts=true`. + schema: + type: integer + minimum: 1 + maximum: 100 + mailserverDomain: + in: query + name: mailserver_domain + description: | + Base search parameter. + Only the registered domain portion of the mail server (e.g., `domaintools.net`). + schema: + $ref: '#/components/schemas/ApexDomain' + mailserverHost: + in: query + name: mailserver_host + description: | + Base search parameter. + Fully-qualified mail server hostname (e.g., mx.domaintools.net). + Performs a Reverse MX lookup to identify domains using this mail server. + schema: + $ref: '#/components/schemas/Fqdn' + mailserverIp: + in: query + name: mailserver_ip + description: | + Base search parameter. + IP address of the mail server. + schema: + $ref: '#/components/schemas/IPv4Address' + matomoCode: + in: query + name: matomo + description: | + Base search parameter. + Matomo tracking code. + schema: + $ref: '#/components/schemas/IdentifierString' + monitorId: + in: query + name: monitor_id + description: Monitor ID from the monitors response - only used when requesting domains for specific monitors. + schema: + type: string + mxExists: + in: query + name: mx_exists + description: Whether domain currently has an MX record in DNS. + schema: + type: boolean + nameserverHost: + in: query + name: nameserver_host + description: | + Base search parameter. + Fully-qualified domain name (FQDN) of the name server. + required: false + schema: + $ref: '#/components/schemas/Hostname' + nameserverDomain: + in: query + name: nameserver_domain + description: | + Base search parameter. + The registered domain name of the nameserver (e.g., `example.com`). + schema: + $ref: '#/components/schemas/Hostname' + nameserverIp: + in: query + name: nameserver_ip + description: | + Base search parameter. + The IPv4 address of the name server. + schema: + $ref: '#/components/schemas/IPv4Address' + nextPageUrl: + in: query + name: next + description: The URL for the next page of search results, emitted as a `next` field in the response, using the `position` marker. + schema: + $ref: '#/components/schemas/BooleanOptInFlag' + notTaggedWithAll: + in: query + name: not_tagged_with_all + description: | + Search filter parameter. + Exclude all domains that are tagged with **all** of the specified tags in the Iris Investigation platform. + This parameter accepts a comma-separated list of tag names. + schema: + $ref: '#/components/schemas/CommaSeparatedTags' + notTaggedWithAny: + in: query + name: not_tagged_with_any + description: | + Search filter parameter. + Exclude all domains that are tagged with **any** of the specified tags in the Iris Investigation platform. + Accepts a comma-separated list of tags. + schema: + $ref: '#/components/schemas/CommaSeparatedTags' + order: + in: query + name: order + description: Specifies the sort order for the results, either ascending or descending. Used in conjunction with the 'sort' parameter. Defaults to `desc`. + schema: + type: string + enum: + - asc + - desc + preview: + in: query + name: preview + description: Use during API implementation and testing. Will limit results to 10 but not be limited by hourly restrictions. + required: false + schema: + $ref: '#/components/schemas/BooleanOptInFlag' + registrar: + in: query + name: registrar + description: | + Base search parameter. + Exact match to the WHOIS registrar field. + schema: + $ref: '#/components/schemas/OrgNameString' + registrant: + in: query + name: registrant + description: | + Base search parameter. + Exact match to the WHOIS registrant field. + schema: + $ref: '#/components/schemas/OrgNameString' + redirectDomain: + in: query + name: redirect_domain + description: | + Base search parameter. + Domains observed to redirect to another domain name. + schema: + $ref: '#/components/schemas/GenericString' + registrantHistoricalWhois: + in: query + name: historical_registrant + description: | + Base search parameter. + Registrant names from historical WHOIS records. + schema: + $ref: '#/components/schemas/OrgNameString' + registrantOrg: + in: query + name: registrant_org + description: | + Base search parameter. + Exact match to the WHOIS registrant organization field + schema: + $ref: '#/components/schemas/OrgNameString' + resultsPosition: + in: query + name: position + description: | + Cursor for paginated results. Use the value returned in a previous response to retrieve the next page. + required: false + schema: + $ref: '#/components/schemas/PositionToken' + dzzzzzzz: + in: query + name: sort_by + description: | + Specifies the field to sort the results by. + schema: + type: string + enum: + - first_seen_since + - create_date + - domain + - risk_score + resultsSortDirection: + in: query + name: sort_direction + description: | + Determines the sort direction, either ascending or descending. + This is used in combination with the 'sort_by' parameter. + schema: + type: string + enum: + - asc + - dsc + riskScoreRanges: + in: query + name: risk_score_ranges + description: | + Filters domains based on their risk score. Multiple ranges can be selected to broaden the filter. Consult [Domain Risk Scores](https://docs.domaintools.com/riskscore/) for help interpreting scores. + schema: + type: array + items: + type: string + enum: + - 0-0 + - 1-39 + - 40-69 + - 70-99 + - 100-100 + style: form + explode: true + irisContainsSearch: + in: query + name: search + description: Performs a `contains` search. + schema: + $ref: '#/components/schemas/BasicString' + searchHash: + in: query + name: search_hash + description: | + Base search parameter. + Token returned by the Iris Investigate UI when exporting a search. + Use this value to import and continue an existing search via the API. + schema: + $ref: '#/components/schemas/SearchHashToken' + serverType: + in: query + name: server_type + description: | + Base search parameter. + Domains hosted on a specific server type (e.g., from the 'Server' HTTP header). Must be an exact match. + schema: + $ref: '#/components/schemas/BasicString' + sortDetect: + in: query + name: sort + description: Sorts the domain list response. Valid fields to sort by are 'discovered_date', 'changed_date', and 'risk_score'. + schema: + type: array + items: + type: string + enum: + - discovered_date + - changed_date + - risk_score + style: form + explode: true + sortMonitorList: + in: query + name: sort[] + description: Provides options for sorting the monitor list. + schema: + type: string + enum: + - term + - created_date + - domain_counts_changed + - domain_counts_discovered + sslAltNames: + in: query + name: ssl_alt_names + description: | + Base search parameter. + Domains with a matching Subject Alternative Name (SAN) in their SSL certificate. + schema: + $ref: '#/components/schemas/GenericString' + sslCommonName: + in: query + name: ssl_common_name + description: | + Base search parameter. + Domains with a matching Common Name (CN) in their SSL certificate's subject. + schema: + $ref: '#/components/schemas/GenericString' + sslDuration: + in: query + name: ssl_duration + description: | + Base search parameter. + Domains with an SSL certificate valid for a specific number of days. + schema: + type: integer + minimum: 1 + sslEmail: + in: query + name: ssl_email + description: | + Base search parameter. + Email address extracted from the SSL certificate associated with a domain. + schema: + $ref: '#/components/schemas/EmailAddress' + sslHash: + in: query + name: ssl_hash + description: | + Base search parameter. + The SHA-1 hash of an SSL certificate, used to filter for domains associated with a specific certificate. + schema: + $ref: '#/components/schemas/Sha1HexString' + sslOrg: + in: query + name: ssl_org + description: | + Base search parameter. + Organization name from the SSL certificate. Must be an exact string match. + schema: + $ref: '#/components/schemas/OrgNameString' + sslSubject: + in: query + name: ssl_subject + description: | + Base search parameter. + Exact match to the Subject distinguished name (DN) string from the SSL certificate. + schema: + $ref: '#/components/schemas/SslSubjectDnString' + statCounterProjectCode: + in: query + name: statcounter_project + description: | + Base search parameter. + Statcounter Project tracker code. + schema: + $ref: '#/components/schemas/IdentifierString' + statCounterSecurityCode: + in: query + name: statcounter_security + description: | + Base search parameter. + Statcounter Security tracker code. + schema: + $ref: '#/components/schemas/IdentifierString' + taggedWithAll: + in: query + name: tagged_with_all + description: | + Search filter parameter. + Comma-separated list of tags. Only returns domains tagged with the full list of tags. + schema: + $ref: '#/components/schemas/GenericString' + taggedWithAny: + in: query + name: tagged_with_any + description: | + Search filter parameter. + Comma-separated list of Iris Investigate tags. Returns domains tagged with any of the tags in a list. + schema: + $ref: '#/components/schemas/GenericString' + tlds: + in: query + name: tlds + description: Filters on specific TLDs + schema: + type: array + items: + type: string + allowReserved: true + style: form + explode: true + topLevelDomain: + in: query + name: tld + description: | + Search filter parameter. + Restrict results to domains under the specified top-level domain (TLD). + schema: + $ref: '#/components/schemas/TopLevelDomain' + websiteTitle: + in: query + name: website_title + description: | + Base search parameter. + The value of the website’s `