{"components":{"headers":{"BuildEtag":{"description":"Weak ETag derived from the running IfPort build marker.","schema":{"example":"W/\"ifport-2026.06.24.1\"","type":"string"}},"BuildId":{"description":"Coherence marker for the running ifport.io build.","schema":{"example":"2026.06.24.1","type":"string"}},"McpCacheControl":{"description":"Successful MCP responses are client-specific and must not be shared or reused by caches.","schema":{"const":"private, no-store","type":"string"}},"PublicCacheControl300":{"description":"Short-lived public cache policy for static public metadata.","schema":{"const":"public, max-age=300","type":"string"}},"PublicCacheControl3600":{"description":"Public cache policy for crawler and well-known metadata.","schema":{"const":"public, max-age=3600","type":"string"}},"PublicCacheControl60":{"description":"Short-lived public cache policy for docs/landing metadata.","schema":{"const":"public, max-age=60","type":"string"}},"RateLimitLimit":{"description":"Request limit for the active rate-limit window.","schema":{"minimum":0,"type":"integer"}},"RateLimitPolicy":{"description":"Applied scan rate-limit class and one-minute burst policy. Current classes are `scan;w=60;burst=30`, `plain;w=60;burst=60`, `custom;w=60;burst=10`, `deep;w=60;burst=3`, and `top1000;w=60;burst=3`.\n","schema":{"example":"scan;w=60;burst=30","type":"string"}},"RateLimitRemaining":{"description":"Remaining requests in the active rate-limit window after this request.","schema":{"minimum":0,"type":"integer"}},"RateLimitReset":{"description":"Seconds until the active rate-limit window resets.","schema":{"minimum":0,"type":"integer"}},"RedirectCacheControl":{"description":"Short-lived cache policy for compatibility redirects.","schema":{"const":"public, max-age=300","type":"string"}},"RequestId":{"description":"Server-generated request correlation ID. For JSON and MCP scan results it is identical to the body request ID and the structured server event request ID. For shared HTTP errors, persisted-result 404 responses, retired 410 responses, and MCP tool errors it matches the body `request_id`; for JSON-RPC transport errors it matches `error.data.request_id`.\n","schema":{"example":"req_0123456789abcdef0123456789abcdef","pattern":"^req_[0-9a-f]{32}$","type":"string"}},"RetryAfter":{"description":"Seconds to wait before retrying after HTTP 429.","schema":{"minimum":1,"type":"integer"}},"ScanCacheControl":{"description":"Scan responses are request-specific and must not be shared or reused by caches.","schema":{"const":"private, no-store","type":"string"}},"ScanVary":{"description":"Root and scan responses vary by representation negotiation.","schema":{"const":"Accept, User-Agent","type":"string"}},"StatusCacheControl":{"description":"Status is live operational state and should not be cached.","schema":{"const":"no-store","type":"string"}}},"parameters":{"DeleteAuthorization":{"description":"Preferred delete-token transport. Use `Bearer <delete_token>` where the token was returned only when a saved result was explicitly created.\n","in":"header","name":"Authorization","required":false,"schema":{"pattern":"^Bearer ifp_[a-f0-9]{32}$","type":"string"}},"DeleteTokenHeader":{"description":"Alternative delete-token transport for clients that cannot set Authorization. Do not send delete tokens in query parameters.\n","in":"header","name":"X-IfPort-Delete-Token","required":false,"schema":{"pattern":"^ifp_[a-f0-9]{32}$","type":"string"}},"EvidenceFormat":{"description":"Force JSON or copy-paste Markdown response from evidence endpoints.","in":"query","name":"format","required":false,"schema":{"enum":["json","markdown","md"],"type":"string"}},"Expand":{"description":"Comma-separated opt-in expansion list for `/json` and `/?format=json`. Supported values are `agent_handoff`, `automation`, `evidence`, `community`, and `all`. Expansion fields are additive and non-funding; they do not include receipt, support proof, provider configuration, social copy, README snippets, or share copy.\n","in":"query","name":"expand","required":false,"schema":{"examples":["evidence,automation","agent_handoff,automation,evidence,community"],"type":"string"}},"ExpectOpen":{"description":"Exact baseline of ports that should be open. Overrides policy with strict exact-match evaluation.","in":"query","name":"expect_open","required":false,"schema":{"example":"443,8443","type":"string"}},"IncludeFullResult":{"description":"Explicitly include the clean core scan payload in `/gate` responses when needed for diagnostics. Omit for compact CI/CD checks. This payload excludes legacy presentation, support, social, and operator-card fields.","in":"query","name":"include_full_result","required":false,"schema":{"enum":["1","true","yes","on"],"type":"string"}},"Intent":{"description":"Defensive interpretation preset for the request source IP. Intent may select bounded profile/policy defaults, but it never accepts arbitrary targets.","in":"query","name":"intent","required":false,"schema":{"enum":["general-exposure","web-deploy","remote-access","database-exposure"],"type":"string"}},"Persist":{"description":"Explicit opt-in to save a public token-addressed result. Default scans are ephemeral and do not create public result permalinks or persisted evidence.\n","in":"query","name":"persist","required":false,"schema":{"default":false,"type":"boolean"}},"Policy":{"description":"Exposure policy gate for CI/ops verdict. `strict` requires no public ports.","in":"query","name":"policy","required":false,"schema":{"default":"strict","enum":["strict","web","remote-admin","database-private","none"],"type":"string"}},"Ports":{"description":"Comma-separated custom TCP ports for the request source IP. Maximum 50 ports with speed=deep.","in":"query","name":"ports","required":false,"schema":{"example":"22,80,443","type":"string"}},"Profile":{"description":"Named scan profile for the request source IP. Ignored when ports is provided. No-parameter requests use compact `default` (22,80,443,3000,8080,8443); use `top1000` for explicit broad verification and `web`, `databases`, or `mail` for focused checks.","in":"query","name":"profile","required":false,"schema":{"default":"default","enum":["default","web","databases","mail","top1000"],"type":"string"}},"ReportFormat":{"description":"Force JSON, HTML, or Markdown response from `/report`.","in":"query","name":"format","required":false,"schema":{"enum":["json","html","markdown","md"],"type":"string"}},"ResultFormat":{"description":"Force JSON, browser HTML, or Markdown response from `/result/{token}`. Default response is browser HTML for `Accept: text/html`, JSON for `Accept: application/json`, and Markdown for CLI-style requests.\n","in":"query","name":"format","required":false,"schema":{"enum":["json","html","markdown","md"],"type":"string"}},"ResultToken":{"description":"Random token returned in `persistence.result_token` only for explicit saved results. This is not an IP, host, target, CIDR, or search parameter, and it is not the internal scan UUID.\n","in":"path","name":"token","required":true,"schema":{"pattern":"^ifp_[a-f0-9]{32}$","type":"string"}},"RootFormat":{"description":"Force a deterministic response representation from `/` regardless of browser, CLI, bot, or Accept-header heuristics. `plain` returns the same newline-separated open-port list shape as `/plain`.\n","in":"query","name":"format","required":false,"schema":{"enum":["json","markdown","md","plain"],"type":"string"}},"RootView":{"description":"Root projection selector. Omitted `view` returns the compact root HTML/Markdown brief. `report` returns the rich root HTML/Markdown compatibility report. For `?format=json`, `core`, deprecated `min`, and omitted `view` return the stable core machine contract; `full` is a compatibility alias for all supported non-funding JSON expansions.\n","in":"query","name":"view","required":false,"schema":{"enum":["report","core","full","min"],"type":"string"}},"Speed":{"description":"Scan speed/depth. When omitted, default, smaller named profiles, custom ports, root, and bounded scan endpoints use balanced. top1000 uses fast unless speed is explicit. Current agent-facing budgets are balanced 650ms per port with a 2500ms global deadline, fast 400ms per port with a 5000ms global deadline, and deep 1200ms per port with a 5000ms global deadline.","in":"query","name":"speed","required":false,"schema":{"default":"balanced","enum":["fast","balanced","deep"],"type":"string"}},"View":{"description":"JSON response projection. Omitted `view`, `core`, and deprecated `min` return the stable core machine contract. `full` is a compatibility alias for explicit non-funding expansions: `agent_handoff,automation,evidence,community`. Funding, receipt, support proof, provider configuration, social copy, README snippets, and share copy are intentionally absent from `/json`. `view` does not change scan execution or scan cache keys.\n","in":"query","name":"view","required":false,"schema":{"default":"core","enum":["core","full","min"],"type":"string"}}},"schemas":{"AutomationKit":{"properties":{"description":{"type":"string"},"expected_open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"id":{"enum":["github-actions","gitlab-ci","cron-bash"],"type":"string"},"snippet":{"type":"string"},"title":{"type":"string"}},"required":["id","title","description","expected_open_ports","snippet"],"type":"object"},"CoreOpenPort":{"additionalProperties":false,"description":"Compact machine-facing open-port item for the stable core contract.","properties":{"port":{"maximum":65535,"minimum":1,"type":"integer"},"protocol":{"const":"tcp","type":"string"},"state":{"const":"open","type":"string"}},"required":["port","protocol","state"],"type":"object"},"CoreVisiblePortsResponse":{"$defs":{"open_port":{"additionalProperties":false,"properties":{"port":{"maximum":65535,"minimum":1,"type":"integer"},"protocol":{"const":"tcp","type":"string"},"state":{"const":"open","type":"string"}},"required":["port","protocol","state"],"type":"object"},"port_error":{"additionalProperties":false,"properties":{"error":{"type":"string"},"port":{"maximum":65535,"minimum":1,"type":"integer"},"protocol":{"const":"tcp","type":"string"}},"required":["port","protocol","error"],"type":"object"}},"$id":"https://ifport.io/schemas/core-visible-ports-response.v1.json","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"example":{"generated_at":"2000-01-01T00:00:00Z","limitations":["This result describes the public request-source path.","If the request passed through NAT, VPN, proxy, CI/CD, cloud runtime, or an LLM sandbox, the result may not describe your local machine.","Unchecked ports are not assessed by the selected profile or explicit port list.","Policy verdicts apply only to the selected bounded policy and selected scan vantage; they are not a security assessment."],"links":{"network_path":"https://ifport.io/network-path","report":"https://ifport.io/report"},"meta":{"build_id":"example-build-not-live","release_sha":"image-example-not-live-0123456789abcdef0123456789abcdef","request_id":"req_0123456789abcdef0123456789abcdef"},"observed_source":{"address_family":"ipv4","attribution_confidence":"high","ip":"203.0.113.42","scope":"public"},"policy":{"name":"strict","unexpected_open_ports":[],"verdict":"pass"},"results":{"closed":[],"errors":[],"filtered_or_timeout":[22,80,443,3000,8080,8443],"open":[]},"scan":{"completed_ports":[22,80,443,3000,8080,8443],"duration_ms":326,"method":"tcp_syn","method_counts":{"tcp_syn":6},"not_attempted_ports":[],"partial":false,"partial_reason":null,"ports_checked":[22,80,443,3000,8080,8443],"profile":"default","speed":"balanced","strategy":"syn_with_connect_fallback","type":"tcp_syn_or_connect","vantage":{"count":1,"id":"primary","region":"eu"}},"schema_version":"1.0","service":"ifport.io"},"properties":{"generated_at":{"description":"Completion time for this bounded response projection.","format":"date-time","type":"string"},"limitations":{"contains":{"const":"Policy verdicts apply only to the selected bounded policy and selected scan vantage; they are not a security assessment."},"items":{"type":"string"},"minItems":4,"type":"array"},"links":{"additionalProperties":false,"properties":{"network_path":{"format":"uri","type":"string"},"report":{"format":"uri","type":"string"}},"required":["network_path","report"],"type":"object"},"meta":{"additionalProperties":false,"properties":{"build_id":{"minLength":1,"type":"string"},"release_sha":{"minLength":1,"type":"string"},"request_id":{"pattern":"^req_[0-9a-f]{32}$","type":"string"}},"required":["build_id","release_sha","request_id"],"type":"object"},"observed_source":{"additionalProperties":false,"properties":{"address_family":{"enum":["ipv4","ipv6","unknown"],"type":"string"},"attribution_confidence":{"enum":["high","medium","low"],"type":"string"},"ip":{"minLength":1,"type":"string"},"scope":{"enum":["public","private","loopback","link_local","documentation","unspecified","unknown","cgnat","benchmark","unique_local"],"type":"string"}},"required":["ip","address_family","scope","attribution_confidence"],"type":"object"},"persistence":{"additionalProperties":false,"properties":{"delete_token":{"pattern":"^ifp_[a-f0-9]{32}$","type":["string","null"]},"delete_url":{"format":"uri","type":["string","null"]},"expires_at":{"format":"date-time","type":["string","null"]},"mode":{"enum":["ephemeral_default","explicit_persist"],"type":"string"},"observed_source_ip_storage":{"enum":["not_persisted_by_default","clear_until_expiry_or_delete"],"type":"string"},"persisted":{"type":"boolean"},"result_evidence_url":{"format":"uri","type":["string","null"]},"result_token":{"pattern":"^ifp_[a-f0-9]{32}$","type":["string","null"]},"result_url":{"format":"uri","type":["string","null"]},"retention_policy":{"enum":["explicit_persist_30d",null],"type":["string","null"]},"robots":{"enum":["not_indexable_no_public_permalink","noindex,noarchive"],"type":"string"}},"required":["persisted","mode","robots","observed_source_ip_storage"],"type":"object"},"policy":{"additionalProperties":false,"description":"Selected bounded policy result for this request-source scan. It is not a security assessment or vulnerability assessment.","properties":{"name":{"description":"Policy name evaluated against the selected bounded port set.","type":"string"},"unexpected_open_ports":{"description":"Open TCP ports that did not match the selected bounded policy expectation.","items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"verdict":{"description":"Raw bounded policy verdict for the current request-source path. A pass only means the selected bounded policy passed; it is not a security assessment or an overall success signal when scan.partial=true.","enum":["pass","warn","fail","not_evaluated"],"type":"string"}},"required":["name","verdict","unexpected_open_ports"],"type":"object"},"results":{"additionalProperties":false,"properties":{"closed":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"errors":{"items":{"$ref":"#/$defs/port_error"},"type":"array"},"filtered_or_timeout":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"open":{"items":{"$ref":"#/$defs/open_port"},"type":"array"}},"required":["open","closed","filtered_or_timeout","errors"],"type":"object"},"scan":{"additionalProperties":false,"allOf":[{"else":{"properties":{"not_attempted_ports":{"maxItems":0},"partial_reason":{"type":"null"}}},"if":{"properties":{"partial":{"const":true}},"required":["partial"]},"then":{"properties":{"not_attempted_ports":{"minItems":1},"partial_reason":{"enum":["global_timeout","worker_partial"]}}}}],"properties":{"completed_ports":{"description":"Ports with a completed probe result before the scan deadline.","items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array","uniqueItems":true},"duration_ms":{"minimum":0,"type":"integer"},"method":{"enum":["tcp_syn","tcp_connect","mixed","not_attempted"],"type":"string"},"method_counts":{"additionalProperties":{"minimum":0,"type":"integer"},"type":"object"},"not_attempted_ports":{"description":"Requested ports not probed before the global scan deadline.","items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array","uniqueItems":true},"partial":{"description":"True when the selected port set did not complete. MCP envelopes mark this as isError=true while retaining the core partial result in structuredContent.","type":"boolean"},"partial_reason":{"description":"Machine-readable reason when partial=true; null when the scan completed.","enum":["global_timeout","worker_partial",null],"type":["string","null"]},"ports_checked":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array","uniqueItems":true},"profile":{"enum":["default","web","databases","mail","top1000","custom"],"type":"string"},"speed":{"description":"Scan timeout profile used for this bounded result.","enum":["fast","balanced","deep"],"type":"string"},"strategy":{"enum":["syn_with_connect_fallback","syn_only","connect_only","unknown"],"type":"string"},"type":{"const":"tcp_syn_or_connect","type":"string"},"vantage":{"additionalProperties":false,"description":"Single-vantage result. Current public scans use one primary EU vantage only.","properties":{"count":{"const":1,"type":"integer"},"id":{"const":"primary","type":"string"},"region":{"const":"eu","type":"string"}},"required":["id","region","count"],"type":"object"}},"required":["type","strategy","method","method_counts","vantage","profile","speed","ports_checked","duration_ms","partial","partial_reason","completed_ports","not_attempted_ports"],"type":"object"},"schema_version":{"const":"1.0","type":"string"},"service":{"const":"ifport.io","type":"string"}},"required":["schema_version","service","generated_at","meta","observed_source","scan","results","policy","limitations","links"],"title":"CoreVisiblePortsResponse","type":"object"},"EdgeHeaderIntegrity":{"additionalProperties":false,"description":"Integrity signal for the direct IfPort HAProxy edge path. The marker is not a secret; it is trusted only after the edge strips inbound forwarding headers, sets X-Real-IP/X-Forwarded-For from the socket source, and the API sees a trusted transport hop.\n","properties":{"header":{"const":"x-ifport-edge-verified","type":"string"},"reason":{"type":"string"},"status":{"enum":["verified_sanitized_edge","not_applicable","missing_edge_marker","untrusted_remote","legacy_forwarding_header_present","header_mismatch","non_public_source","unverified"],"type":"string"},"verified":{"type":"boolean"}},"required":["verified","status","header","reason"],"type":"object"},"ErrorResponse":{"$id":"https://ifport.io/schemas/error-response.v1.json","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"error":{"additionalProperties":false,"properties":{"code":{"examples":["invalid_request","invalid_ports","invalid_profile","invalid_format","invalid_view","invalid_result_token","invalid_delete_token","forbidden","method_not_allowed","not_found","policy_gate_failed","endpoint_gone","persisted_result_not_found","rate_limited","service_unavailable"],"type":"string"},"message":{"type":"string"},"request_id":{"examples":["req_0123456789abcdef0123456789abcdef"],"pattern":"^req_[0-9a-f]{32}$","type":"string"}},"required":["code","message","request_id"],"type":"object"}},"required":["error"],"title":"ErrorResponse","type":"object"},"EvidenceCopyPaste":{"properties":{"ci_verify_command":{"type":"string"},"gate_command":{"type":"string"},"markdown":{"type":"string"},"network_path_command":{"type":"string"},"report_command":{"type":"string"},"save_verify_payload_command":{"type":"string"},"slack_text":{"type":"string"},"verify_command":{"type":"string"},"verify_keys_command":{"type":"string"}},"required":["markdown","slack_text","save_verify_payload_command","verify_command","ci_verify_command","verify_keys_command","report_command","gate_command","network_path_command"],"type":"object"},"EvidenceLinks":{"properties":{"network_path":{"type":"string"},"report":{"type":"string"},"verify":{"type":"string"},"verify_keys":{"type":"string"}},"required":["verify","verify_keys","report","network_path"],"type":"object"},"EvidenceResponse":{"properties":{"boundary":{"$ref":"#/components/schemas/RequestSourceBoundary"},"confidence":{"enum":["high","medium","low"],"type":"string"},"copy_paste":{"$ref":"#/components/schemas/EvidenceCopyPaste"},"decision":{"enum":["allow","review","block"],"type":"string"},"drift":{"$ref":"#/components/schemas/ScanDrift"},"generated_at":{"format":"date-time","type":"string"},"limitations":{"items":{"type":"string"},"type":"array"},"links":{"$ref":"#/components/schemas/EvidenceLinks"},"observed_source":{"additionalProperties":false,"properties":{"address_family":{"enum":["ipv4","ipv6","unknown"],"type":"string"},"attribution_confidence":{"enum":["high","medium","low"],"type":"string"},"ip":{"description":"IP address ifport.io observed for this request-source path.","type":"string"},"scope":{"enum":["public","private","cgnat","loopback","link_local","unique_local","documentation","benchmark","invalid_or_unknown"],"type":"string"}},"required":["ip","address_family","scope","attribution_confidence"],"type":"object"},"observed_source_ip":{"type":"string"},"open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"partial":{"type":"boolean"},"profile":{"type":"string"},"snapshot":{"$ref":"#/components/schemas/ScanSnapshot"},"status":{"const":"ok","type":"string"},"unexpected_open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"verdict":{"enum":["pass","warn","fail","not_evaluated"],"type":"string"},"verify_payload":{"$ref":"#/components/schemas/SnapshotVerifyRequest"}},"required":["status","generated_at","observed_source","observed_source_ip","profile","decision","verdict","confidence","open_ports","unexpected_open_ports","partial","drift","snapshot","verify_payload","copy_paste","boundary","limitations","links"],"type":"object"},"GateAction":{"additionalProperties":false,"description":"Machine-readable next step for CI and agent clients. It does not include legacy presentation, support, social, or operator-card fields.","properties":{"likely_issue":{"description":"Stable reason code for the most likely bounded follow-up.","type":"string"},"links":{"$ref":"#/components/schemas/GateActionLinks"},"next_action":{"description":"Short action that keeps the request-source-only boundary.","type":"string"},"next_command":{"description":"Copy-paste command for the recommended bounded follow-up.","type":"string"}},"required":["likely_issue","next_action","next_command","links"],"type":"object"},"GateActionLinks":{"additionalProperties":false,"description":"Stable follow-up links for compact /gate clients.","properties":{"gate":{"description":"Canonical gate URL for rerunning the current bounded baseline from the same request-source path.","format":"uri","type":"string"},"network_path":{"description":"Diagnostic endpoint for source attribution, NAT, proxy, VPN, CI, and cloud-runtime ambiguity.","format":"uri","type":"string"},"report":{"description":"Human-readable report URL for the same bounded request-source baseline.","format":"uri","type":"string"},"verify":{"description":"Snapshot verification endpoint for persisted gate evidence.","format":"uri","type":"string"}},"required":["gate","report","network_path","verify"],"type":"object"},"GateResponse":{"description":"Bounded policy-gate result for the current request-source scan. This object is not a security assessment or vulnerability assessment. A pass requires every selected port to complete before the scan deadline.\n","properties":{"action":{"$ref":"#/components/schemas/GateAction"},"completed_ports_count":{"description":"Number of selected ports with an actual probe result before the gate deadline.","minimum":0,"type":"integer"},"coverage":{"$ref":"#/components/schemas/ScanCoverage"},"error":{"$ref":"#/components/schemas/ErrorResponse/properties/error","description":"Present only on HTTP 409 blocked responses. Kept compatible with the shared ErrorResponse object so existing CI clients can keep parsing `error.code=policy_gate_failed` while newer clients read the structured gate verdict and snapshot fields.\n"},"full_result":{"$ref":"#/components/schemas/CoreVisiblePortsResponse","description":"Optional clean core scan payload; present only when `include_full_result=true`. It excludes legacy presentation, support, social, and operator-card fields."},"not_attempted_ports":{"description":"Selected ports that were not probed before the global scan deadline.","items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"note":{"description":"Human-readable gate note. For pass, the selected bounded policy passed; for not_evaluated, no bounded policy verdict was evaluated; for partial, incomplete coverage prevents success. It is not a security assessment.","type":"string"},"observed_source":{"additionalProperties":false,"properties":{"address_family":{"enum":["ipv4","ipv6","unknown"],"type":"string"},"attribution_confidence":{"enum":["high","medium","low"],"type":"string"},"ip":{"description":"IP address ifport.io observed for this request-source path.","type":"string"},"scope":{"enum":["public","private","cgnat","loopback","link_local","unique_local","documentation","benchmark","invalid_or_unknown"],"type":"string"}},"required":["ip","address_family","scope","attribution_confidence"],"type":"object"},"observed_source_ip":{"type":"string"},"partial":{"description":"True when the worker did not complete the full selected port set. A partial scan never passes the gate.","type":"boolean"},"partial_reason":{"description":"Machine-readable incomplete-scan reason; null only when partial=false.","enum":["global_timeout","worker_partial",null],"type":["string","null"]},"policy_verdict":{"description":"Raw bounded policy verdict before request-source attribution gating. This can differ from `verdict`: for example a strict policy can pass while the combined gate verdict is warn because the observed source path has low attribution confidence.\n","enum":["pass","warn","fail","not_evaluated"],"type":"string"},"profile":{"type":"string"},"reason_code":{"description":"Stable machine-readable reason for a completed public-source gate verdict. Use this to distinguish bounded-policy failures, incomplete coverage, and low-confidence public-source attribution outcomes. Non-public observed sources return ErrorResponse `invalid_request` with `/network-path` guidance instead.\n","enum":["bounded_policy_passed","bounded_policy_not_evaluated","partial_scan","low_confidence_observation_path","policy_requires_review","open_ports_need_owner_validation","unexpected_public_exposure","manual_intent_validation_required","web_ingress_not_visible","web_ingress_visible_with_unexpected_exposure","remote_access_publicly_visible","database_port_publicly_visible","expected_ports_not_visible","gate_verdict_unknown"],"type":"string"},"scan_result":{"enum":["no_open_ports_detected","open_ports_detected"],"type":"string"},"security_assurance":{"description":"IfPort reports bounded TCP visibility only and does not assess host security.","enum":["not_assessed"],"type":"string"},"snapshot_id":{"type":"string"},"snapshot_sha256":{"type":"string"},"status":{"enum":["ok","blocked"],"type":"string"},"verdict":{"description":"A pass only means the selected bounded policy passed for the current request-source path; it is not a security assessment.\n","enum":["pass","warn","fail","not_evaluated"],"type":"string"}},"required":["status","verdict","reason_code","observed_source","observed_source_ip","profile","scan_result","policy_verdict","coverage","partial","partial_reason","completed_ports_count","not_attempted_ports","security_assurance","snapshot_id","snapshot_sha256","action","note"],"type":"object"},"HealthResponse":{"properties":{"build_id":{"type":"string"},"release_sha":{"type":"string"},"safe_mode":{"$ref":"#/components/schemas/SafeModeStatus"},"scan_workers":{"properties":{"ready":{"minimum":0,"type":"integer"},"registered":{"minimum":0,"type":"integer"}},"required":["registered","ready"],"type":"object"},"service":{"type":"string"},"status":{"type":"string"},"timestamp":{"format":"date-time","type":"string"},"uptimeSeconds":{"minimum":0,"type":"integer"},"version":{"type":"string"}},"required":["status","service","version","build_id","release_sha","uptimeSeconds","timestamp","scan_workers","safe_mode"],"type":"object"},"JsonExpandedVisiblePortsResponse":{"allOf":[{"$ref":"#/components/schemas/CoreVisiblePortsResponse"},{"properties":{"accuracy":{"additionalProperties":true,"type":"object"},"agent_handoff":{"additionalProperties":true,"type":"object"},"assessment":{"additionalProperties":true,"type":"object"},"automation":{"additionalProperties":true,"type":"object"},"cache":{"additionalProperties":true,"type":"object"},"community":{"additionalProperties":true,"type":"object"},"decision":{"additionalProperties":true,"type":"object"},"drift":{"$ref":"#/components/schemas/ScanDrift"},"evidence":{"additionalProperties":true,"type":"object"},"intent":{"additionalProperties":true,"type":"object"},"network":{"additionalProperties":true,"type":"object"},"snapshot":{"$ref":"#/components/schemas/ScanSnapshot"},"triage":{"additionalProperties":true,"type":"object"}},"type":"object"}],"description":"`/json` response when `expand` is explicitly set, or when compatibility `view=full` is used. It starts with CoreVisiblePortsResponse and adds only the requested non-funding expansion blocks. Receipt, support proof, provider configuration, social copy, README snippets, and share copy are intentionally absent.\n","type":"object"},"McpJsonRpcErrorResponse":{"additionalProperties":false,"example":{"error":{"code":-32700,"data":{"request_id":"req_0123456789abcdef0123456789abcdef"},"message":"Parse error"},"id":null,"jsonrpc":"2.0"},"properties":{"error":{"additionalProperties":false,"properties":{"code":{"examples":[-32700,-32600,-32000],"type":"integer"},"data":{"additionalProperties":false,"description":"Server-generated correlation metadata. Matches the X-Request-Id response header.","properties":{"request_id":{"pattern":"^req_[0-9a-f]{32}$","type":"string"}},"required":["request_id"],"type":"object"},"message":{"type":"string"}},"required":["code","message","data"],"type":"object"},"id":{"description":"Request id when it can be recovered; null for malformed JSON.","oneOf":[{"type":"integer"},{"type":"string"},{"type":"null"}]},"jsonrpc":{"const":"2.0","type":"string"}},"required":["jsonrpc","id","error"],"type":"object"},"MinimalVisiblePortsResponse":{"allOf":[{"$ref":"#/components/schemas/CoreVisiblePortsResponse"}],"deprecated":true,"description":"Deprecated schema alias for CoreVisiblePortsResponse; `view=min` now returns the core projection."},"NetworkHeaderCandidates":{"properties":{"cf_connecting_ip":{"type":["string","null"]},"forwarded":{"type":["string","null"]},"x_forwarded_for_first_public":{"description":"First public IP parsed from `X-Forwarded-For` after trusted edge sanitization. Null when the header has no public IP candidate; this field does not report private fallback candidates.\n","type":["string","null"]},"x_real_ip":{"type":["string","null"]}},"required":["cf_connecting_ip","forwarded","x_forwarded_for_first_public","x_real_ip"],"type":"object"},"NetworkPathAttribution":{"properties":{"confidence":{"enum":["high","medium","low"],"type":"string"},"message":{"type":"string"},"representation":{"enum":["direct_request_path","verified_edge_header","trusted_edge_header","translated_or_proxy_path","unknown_path"],"type":"string"},"risks":{"items":{"type":"string"},"type":"array"},"verdict":{"enum":["direct_public_path","trusted_edge_header_path","translated_or_private_path"],"type":"string"}},"required":["verdict","confidence","representation","message","risks"],"type":"object"},"NetworkPathCopyPaste":{"properties":{"curl_commands":{"items":{"type":"string"},"type":"array"},"markdown":{"type":"string"}},"required":["markdown","curl_commands"],"type":"object"},"NetworkPathLinks":{"properties":{"docs":{"type":"string"},"evidence":{"type":"string"},"json":{"type":"string"},"run_check":{"type":"string"},"support":{"type":"string"}},"required":["run_check","json","evidence","docs","support"],"type":"object"},"NetworkPathResponse":{"properties":{"accuracy":{"properties":{"confidence":{"enum":["high","medium","low"],"type":"string"},"next_steps":{"items":{"type":"string"},"type":"array"},"observed_ip_scope":{"enum":["public","private","cgnat","loopback","link_local","unique_local","documentation","benchmark","invalid_or_unknown"],"type":"string"},"reasons":{"items":{"type":"string"},"type":"array"},"representation":{"enum":["direct_request_path","verified_edge_header","trusted_edge_header","translated_or_proxy_path","unknown_path"],"type":"string"}},"required":["representation","confidence","observed_ip_scope","reasons","next_steps"],"type":"object"},"attribution":{"$ref":"#/components/schemas/NetworkPathAttribution"},"copy_paste":{"$ref":"#/components/schemas/NetworkPathCopyPaste"},"edge_header_integrity":{"$ref":"#/components/schemas/EdgeHeaderIntegrity"},"fix_playbook":{"items":{"type":"string"},"type":"array"},"ip_source":{"enum":["transport_remote_ip","x_real_ip_trusted_proxy","cf_connecting_ip_trusted_proxy","forwarded_trusted_proxy","x_forwarded_for_trusted_proxy"],"type":"string"},"limitations":{"items":{"type":"string"},"type":"array"},"links":{"$ref":"#/components/schemas/NetworkPathLinks"},"notes":{"items":{"type":"string"},"type":"array"},"observed_ip_scope":{"enum":["public","private","cgnat","loopback","link_local","unique_local","documentation","benchmark","invalid_or_unknown"],"type":"string"},"observed_source":{"additionalProperties":false,"description":"Core-compatible request-source path summary for agent parsing.","properties":{"address_family":{"enum":["ipv4","ipv6","unknown"],"type":"string"},"attribution_confidence":{"enum":["high","medium","low"],"type":"string"},"ip":{"type":"string"},"scope":{"enum":["public","private","cgnat","loopback","link_local","unique_local","documentation","benchmark","invalid_or_unknown"],"type":"string"}},"required":["ip","address_family","scope","attribution_confidence"],"type":"object"},"observed_source_ip":{"type":"string"},"service":{"const":"ifport.io","type":"string"},"status":{"const":"ok","type":"string"},"transport_remote_ip":{"type":["string","null"]},"trusted_header_candidates":{"$ref":"#/components/schemas/NetworkHeaderCandidates"},"verify_commands":{"items":{"type":"string"},"type":"array"}},"required":["status","service","observed_source","observed_source_ip","observed_ip_scope","ip_source","trusted_header_candidates","edge_header_integrity","attribution","accuracy","fix_playbook","verify_commands","copy_paste","links","limitations","notes"],"type":"object"},"OpenPort":{"deprecated":true,"description":"Legacy rich open-port item retained only for compatibility projections. Compact/current contracts use CoreOpenPort and do not expose operator runbooks.\n","properties":{"agent_recommendation":{"type":"string"},"common_service":{"type":["string","null"]},"confidence":{"const":"port_mapping_only","type":"string"},"latency_ms":{"type":["integer","null"]},"operator_runbook":{"$ref":"#/components/schemas/PortExposureRunbook"},"port":{"maximum":65535,"minimum":1,"type":"integer"},"protocol":{"const":"tcp","type":"string"},"risk_hint":{"type":"string"},"state":{"const":"open","type":"string"}},"required":["port","protocol","state","confidence","risk_hint","agent_recommendation","operator_runbook"],"type":"object"},"PersistedEvidenceResponse":{"properties":{"boundary":{"$ref":"#/components/schemas/RequestSourceBoundary"},"closed_or_filtered_count":{"minimum":0,"type":"integer"},"copy_paste":{"properties":{"curl_command":{"type":"string"},"markdown":{"type":"string"},"slack_text":{"type":"string"}},"required":["markdown","slack_text","curl_command"],"type":"object"},"event_id":{"type":"string"},"evidence":{"properties":{"evidence_id":{"type":"string"},"evidence_version":{"const":"persisted_evidence.v1","type":"string"},"fingerprint_sha256":{"type":"string"},"signature":{"$ref":"#/components/schemas/ScanSnapshotSignature","nullable":true},"signed_payload":{"const":"persisted_scan_observed_evidence_v1","type":"string"}},"required":["evidence_version","evidence_id","fingerprint_sha256","signed_payload"],"type":"object"},"evidence_type":{"const":"persisted_scan_observed_evidence","type":"string"},"expires_at":{"format":"date-time","type":"string"},"generated_at":{"format":"date-time","type":"string"},"integrity_payload":{"description":"Canonical JSON object hashed by `evidence.fingerprint_sha256`; it is derived from stored scan_events data and does not trigger a scan.","type":"object"},"limitations":{"items":{"type":"string"},"type":"array"},"links":{"properties":{"openapi":{"format":"uri","type":"string"},"privacy":{"format":"uri","type":"string"},"result_card_svg_url":{"format":"uri","type":"string"},"result_evidence_url":{"format":"uri","type":"string"},"result_url":{"format":"uri","type":"string"},"run_fresh_check":{"format":"uri","type":"string"},"terms":{"format":"uri","type":"string"}},"required":["result_url","result_card_svg_url","result_evidence_url","run_fresh_check","privacy","terms","openapi"],"type":"object"},"observed_source":{"$ref":"#/components/schemas/PersistedResultResponse/properties/observed_source"},"observed_source_ip":{"type":"string"},"observed_source_ip_storage":{"const":"clear_until_expiry_or_delete","type":"string"},"open_ports":{"items":{"$ref":"#/components/schemas/PersistedResultResponse/properties/open_ports/items"},"type":"array"},"ports_checked_count":{"minimum":0,"type":"integer"},"ports_checked_hash_sha256":{"type":"string"},"ports_checked_preview":{"description":"Short preview of checked TCP ports. The full canonical list is in `integrity_payload`.","items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"result_token":{"pattern":"^ifp_[a-f0-9]{32}$","type":"string"},"retention_policy":{"const":"explicit_persist_30d","type":"string"},"scan":{"$ref":"#/components/schemas/PersistedResultResponse/properties/scan"},"scan_id":{"format":"uuid","type":"string"},"service":{"const":"ifport.io","type":"string"},"status":{"const":"ok","type":"string"},"target":{"properties":{"ip":{"type":"string"},"type":{"const":"request_source_ip","type":"string"}},"required":["type","ip"],"type":"object"}},"required":["status","service","evidence_type","generated_at","result_token","scan_id","event_id","expires_at","retention_policy","observed_source_ip_storage","observed_source_ip","observed_source","target","scan","open_ports","closed_or_filtered_count","ports_checked_count","ports_checked_preview","ports_checked_hash_sha256","evidence","integrity_payload","copy_paste","boundary","limitations","links"],"type":"object"},"PersistedResultResponse":{"properties":{"closed_or_filtered_count":{"minimum":0,"type":"integer"},"event_id":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"limitations":{"items":{"type":"string"},"type":"array"},"links":{"properties":{"openapi":{"format":"uri","type":"string"},"privacy":{"format":"uri","type":"string"},"result_card_svg_url":{"format":"uri","type":"string"},"result_evidence_url":{"description":"Read-only persisted evidence pack derived from stored scan_events data. Opening it does not run a scan.","format":"uri","type":"string"},"result_url":{"format":"uri","type":"string"},"run_check":{"format":"uri","type":"string"},"terms":{"format":"uri","type":"string"}},"required":["run_check","result_url","result_card_svg_url","result_evidence_url","privacy","terms","openapi"],"type":"object"},"observed_source":{"description":"Canonical request-source summary for the stored scan. The legacy `target` field is retained for compatibility and must always describe the same request-source IP.","properties":{"address_family":{"enum":["ipv4","ipv6","unknown"],"type":"string"},"attribution_confidence":{"enum":["high","medium","low"],"type":"string"},"ip":{"type":"string"},"scope":{"type":"string"}},"required":["ip","address_family","scope","attribution_confidence"],"type":"object"},"observed_source_ip":{"type":"string"},"observed_source_ip_storage":{"const":"clear_until_expiry_or_delete","type":"string"},"open_ports":{"items":{"properties":{"common_service":{"nullable":true,"type":"string"},"confidence":{"nullable":true,"type":"string"},"latency_ms":{"minimum":0,"nullable":true,"type":"integer"},"port":{"maximum":65535,"minimum":1,"type":"integer"},"protocol":{"const":"tcp","type":"string"},"risk_hint":{"nullable":true,"type":"string"},"state":{"type":"string"}},"required":["port","protocol","state"],"type":"object"},"type":"array"},"result_token":{"pattern":"^ifp_[a-f0-9]{32}$","type":"string"},"result_type":{"const":"persisted_scan_result","type":"string"},"retention_policy":{"const":"explicit_persist_30d","type":"string"},"scan":{"properties":{"duration_ms":{"minimum":0,"type":"integer"},"finished_at":{"format":"date-time","type":"string"},"open_port_count":{"minimum":0,"type":"integer"},"ports_checked_count":{"description":"Number of bounded TCP ports checked by the original scan. The persisted response intentionally does not repeat every checked port.","minimum":0,"type":"integer"},"profile":{"type":"string"},"requested_at":{"format":"date-time","type":"string"},"route":{"type":"string"},"status":{"type":"string"},"timeout_ms":{"minimum":0,"type":"integer"},"type":{"type":"string"}},"required":["route","profile","type","status","ports_checked_count","timeout_ms","requested_at","finished_at","duration_ms","open_port_count"],"type":"object"},"scan_id":{"format":"uuid","type":"string"},"service":{"const":"ifport.io","type":"string"},"status":{"const":"ok","type":"string"},"target":{"properties":{"ip":{"type":"string"},"type":{"const":"request_source_ip","type":"string"}},"required":["type","ip"],"type":"object"}},"required":["status","service","result_type","result_token","scan_id","event_id","expires_at","retention_policy","observed_source_ip_storage","observed_source_ip","observed_source","target","scan","open_ports","closed_or_filtered_count","limitations","links"],"type":"object"},"PortError":{"properties":{"error":{"type":"string"},"port":{"maximum":65535,"minimum":1,"type":"integer"},"protocol":{"const":"tcp","type":"string"}},"required":["port","protocol","error"],"type":"object"},"PortExposureRunbook":{"deprecated":true,"description":"Compatibility-only operator runbook used by legacy rich projections.","properties":{"category":{"enum":["remote_admin","data_service","container_or_control_plane","public_web","proxy_or_messaging","source_attribution","unknown_service"],"type":"string"},"hardening_actions":{"items":{"type":"string"},"type":"array"},"immediate_checks":{"items":{"type":"string"},"type":"array"},"owner_question":{"type":"string"},"verify_commands":{"items":{"type":"string"},"type":"array"}},"required":["category","owner_question","immediate_checks","hardening_actions","verify_commands"],"type":"object"},"RequestSourceBoundary":{"description":"Request-source-only boundary used by current evidence and persisted-result schemas.","properties":{"arbitrary_targets_allowed":{"type":"boolean"},"cidr_scanning_allowed":{"type":"boolean"},"exploitation_allowed":{"type":"boolean"},"request_source_only":{"type":"boolean"}},"required":["request_source_only","arbitrary_targets_allowed","cidr_scanning_allowed","exploitation_allowed"],"type":"object"},"SafeModeStatus":{"properties":{"deep_enabled":{"description":"Whether the expensive `speed=deep` scan mode is enabled.","type":"boolean"},"expensive_enrichments_enabled":{"description":"Whether optional aggregate/community enrichment blocks are enabled. When false, rich payloads return a schema-compatible `community_unavailable` block without loading aggregate data.","type":"boolean"},"result_persistence_enabled":{"description":"Whether explicit saved-result persistence is enabled.","type":"boolean"},"share_generation_enabled":{"description":"Whether share/card copy and persisted result SVG card generation are enabled. When false, `/result/{token}.svg` returns 503 while result JSON and evidence remain available.","type":"boolean"},"support_injection_enabled":{"description":"Whether support/donation prompts may be injected into rich scan responses. When false, rich payloads use neutral safe-mode text and static `/support` and `/donate` remain available.","type":"boolean"},"top1000_enabled":{"description":"Whether the explicit broad `profile=top1000` scan mode is enabled.","type":"boolean"}},"required":["top1000_enabled","deep_enabled","result_persistence_enabled","share_generation_enabled","support_injection_enabled","expensive_enrichments_enabled"],"type":"object"},"ScanCoverage":{"properties":{"ports_checked_count":{"minimum":0,"type":"integer"},"profile":{"type":"string"}},"required":["profile","ports_checked_count"],"type":"object"},"ScanDefaults":{"example":{"ports":[22,80,443,3000,8080,8443],"ports_checked_count":6,"profile":"default","speed":"balanced"},"properties":{"ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"maxItems":6,"minItems":6,"type":"array"},"ports_checked_count":{"const":6,"type":"integer"},"profile":{"const":"default","type":"string"},"speed":{"const":"balanced","type":"string"}},"required":["profile","speed","ports","ports_checked_count"],"type":"object"},"ScanDrift":{"additionalProperties":false,"description":"Comparison context for the same observed request-source scan scope. Drift is not part of the signed snapshot fingerprint and may come from runtime memory or explicit saved-result history.\n","properties":{"closed_since_last":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"new_open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"note":{"type":"string"},"previous_scan_time":{"format":"date-time","type":["string","null"]},"source":{"enum":["postgres_scan_events","runtime_memory","unavailable"],"type":"string"},"status":{"enum":["first_seen","unchanged","changed","unknown"],"type":"string"}},"required":["source","status","previous_scan_time","new_open_ports","closed_since_last","note"],"type":"object"},"ScanSnapshot":{"properties":{"fingerprint_sha256":{"type":"string"},"signature":{"$ref":"#/components/schemas/SnapshotVerifySignature","nullable":true},"snapshot_id":{"type":"string"},"verification":{"type":"string"},"version":{"type":"string"}},"required":["version","snapshot_id","fingerprint_sha256","verification"],"type":"object"},"SnapshotKeyRotation":{"properties":{"note":{"type":"string"},"previous_keys_supported":{"type":"boolean"},"status":{"enum":["supported"],"type":"string"}},"required":["status","previous_keys_supported","note"],"type":"object"},"SnapshotPublicKey":{"properties":{"algorithm":{"const":"ed25519","type":"string"},"key_id":{"type":"string"},"not_after":{"nullable":true,"type":"string"},"not_before":{"nullable":true,"type":"string"},"public_key_hex":{"pattern":"^[0-9a-f]{64}$","type":"string"},"status":{"enum":["current","previous"],"type":"string"}},"required":["key_id","algorithm","public_key_hex","status"],"type":"object"},"SnapshotSignatureCanonicalization":{"properties":{"payloads":{"properties":{"persisted_evidence":{"const":"persisted_scan_observed_evidence_v1","type":"string"},"scan_snapshot":{"const":"scan_snapshot_fingerprint_source_v1","type":"string"}},"required":["scan_snapshot","persisted_evidence"],"type":"object"},"signature_base":{"const":"ifport_signature_envelope_v1","type":"string"},"signature_envelope_fields":{"items":{"type":"string"},"type":"array"},"signature_envelope_version":{"const":1,"type":"integer"},"signature_serialization":{"const":"rfc8785_jcs(ifport_signature_envelope_v1)","type":"string"}},"required":["signature_base","signature_serialization","signature_envelope_version","signature_envelope_fields","payloads"],"type":"object"},"SnapshotVerifyKeysResponse":{"properties":{"algorithm":{"const":"ed25519","type":"string"},"canonicalization":{"$ref":"#/components/schemas/SnapshotSignatureCanonicalization"},"current_key_id":{"nullable":true,"type":"string"},"endpoint":{"const":"/verify/keys","type":"string"},"generated_at":{"format":"date-time","type":"string"},"keys":{"items":{"$ref":"#/components/schemas/SnapshotPublicKey"},"type":"array"},"rotation":{"$ref":"#/components/schemas/SnapshotKeyRotation"},"service":{"const":"ifport.io","type":"string"},"status":{"const":"ok","type":"string"}},"required":["status","service","endpoint","algorithm","generated_at","current_key_id","keys","canonicalization","rotation"],"type":"object"},"SnapshotVerifyRequest":{"additionalProperties":false,"properties":{"closed_or_filtered_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"fingerprint_sha256":{"type":"string"},"observed_source_ip":{"type":"string"},"open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"partial":{"type":"boolean"},"policy_missing_expected_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"policy_name":{"type":"string"},"policy_unexpected_open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"policy_verdict":{"type":"string"},"ports_checked":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"profile":{"type":"string"},"signature":{"$ref":"#/components/schemas/SnapshotVerifySignature","nullable":true},"snapshot_id":{"type":"string"},"speed":{"type":"string"}},"required":["observed_source_ip","profile","speed","ports_checked","open_ports","closed_or_filtered_ports","partial","policy_name","policy_verdict","policy_unexpected_open_ports","policy_missing_expected_ports","snapshot_id","fingerprint_sha256"],"type":"object"},"SnapshotVerifyResponse":{"properties":{"computed_fingerprint_sha256":{"type":"string"},"computed_snapshot_id":{"type":"string"},"fingerprint_match":{"type":"boolean"},"note":{"type":"string"},"signature_provided":{"type":"boolean"},"signature_result":{"enum":["match","mismatch","key_unavailable","key_id_mismatch","public_key_mismatch","invalid_hex","payload_hash_mismatch","invalid_timestamp","invalid_lifetime","expired","algorithm_mismatch","signed_payload_mismatch","signature_base_mismatch","canonicalization_mismatch"],"nullable":true,"type":"string"},"signature_verified":{"nullable":true,"type":"boolean"},"snapshot_id_match":{"type":"boolean"},"status":{"const":"ok","type":"string"},"verified":{"type":"boolean"}},"required":["status","verified","fingerprint_match","snapshot_id_match","computed_fingerprint_sha256","computed_snapshot_id","signature_provided","note"],"type":"object"},"SnapshotVerifySignature":{"additionalProperties":false,"properties":{"algorithm":{"const":"ed25519","type":"string"},"canonicalization":{"const":"rfc8785_jcs(ifport_signature_envelope_v1)","description":"RFC 8785 JSON Canonicalization Scheme bytes for the signature envelope.","type":"string"},"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"key_id":{"type":"string"},"payload_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"public_key_hex":{"description":"Lowercase hex-encoded Ed25519 public key for this key_id.","pattern":"^[0-9a-f]{64}$","type":"string"},"signature_base":{"const":"ifport_signature_envelope_v1","type":"string"},"signature_hex":{"description":"Lowercase hex-encoded Ed25519 signature.","pattern":"^[0-9a-f]{128}$","type":"string"},"signed_payload":{"const":"scan_snapshot_fingerprint_source_v1","type":"string"}},"required":["algorithm","key_id","public_key_hex","signature_hex","signed_payload","signature_base","canonicalization","payload_sha256","created_at","expires_at"],"type":"object"},"SupportIntent":{"properties":{"action_label":{"type":"string"},"agent_instruction":{"type":"string"},"copy_paste_markdown":{"type":"string"},"donate_url":{"type":"string"},"intent":{"const":"support_ifport_public_defensive_utility","type":"string"},"monthly_gap_usd":{"minimum":0,"type":"integer"},"nearest_unlock_gap_usd":{"minimum":0,"type":"integer"},"nearest_unlock_id":{"type":"string"},"nearest_unlock_outcome":{"type":"string"},"no_paid_access_note":{"type":"string"},"procurement_note":{"type":"string"},"provider_status":{"enum":["configured","provider_missing"],"type":"string"},"status":{"enum":["ready_to_donate","provider_pending"],"type":"string"},"subject":{"type":"string"}},"required":["intent","status","donate_url","action_label","provider_status","monthly_gap_usd","nearest_unlock_id","nearest_unlock_gap_usd","nearest_unlock_outcome","subject","copy_paste_markdown","procurement_note","agent_instruction","no_paid_access_note"],"type":"object"},"SupportLink":{"properties":{"provider":{"description":"Provider identifier such as github_sponsors, ko_fi, stripe, open_collective, primary, or a configured custom provider.","type":"string"},"url":{"format":"uri","type":"string"}},"required":["provider","url"],"type":"object"},"SupportProviderSetup":{"properties":{"message":{"type":"string"},"status":{"enum":["configured","provider_missing"],"type":"string"}},"required":["status","message"],"type":"object"},"SupportTier":{"properties":{"amount_usd":{"minimum":1,"type":"integer"},"id":{"type":"string"},"impact":{"type":"string"},"label":{"type":"string"}},"required":["id","amount_usd","label","impact"],"type":"object"},"TrustPortExposure":{"properties":{"common_service":{"nullable":true,"type":"string"},"open_observations":{"minimum":0,"type":"integer"},"port":{"maximum":65535,"minimum":1,"type":"integer"},"risk_hint":{"type":"string"},"unique_source_ips":{"minimum":0,"type":"integer"}},"required":["port","common_service","open_observations","unique_source_ips","risk_hint"],"type":"object"},"TrustResponse":{"properties":{"build_id":{"type":"string"},"contacts":{"properties":{"abuse":{"const":"abuse@ifport.io","type":"string"},"security":{"const":"security@ifport.io","type":"string"}},"required":["security","abuse"],"type":"object"},"defaults":{"$ref":"#/components/schemas/ScanDefaults","example":{"ports":[22,80,443,3000,8080,8443],"ports_checked_count":6,"profile":"default","speed":"balanced"}},"generated_at":{"description":"Time when this no-scan trust response was assembled.","format":"date-time","type":"string"},"links":{"properties":{"docs":{"type":"string"},"openapi":{"type":"string"},"security":{"type":"string"},"status":{"type":"string"},"support":{"type":"string"}},"required":["docs","status","security","support","openapi"],"type":"object"},"promise":{"properties":{"arbitrary_targets_allowed":{"const":false,"type":"boolean"},"cidr_scanning_allowed":{"const":false,"type":"boolean"},"exploitation_allowed":{"const":false,"type":"boolean"},"request_source_only":{"const":true,"type":"boolean"}},"required":["request_source_only","arbitrary_targets_allowed","cidr_scanning_allowed","exploitation_allowed"],"type":"object"},"quality":{"$ref":"#/components/schemas/TrustRuntimeQuality"},"release_sha":{"type":"string"},"reliability":{"$ref":"#/components/schemas/TrustRuntimeReliability"},"service":{"const":"ifport.io","type":"string"},"status":{"const":"ok","type":"string"},"transparency":{"$ref":"#/components/schemas/TrustTransparencySummary"}},"required":["status","service","build_id","release_sha","generated_at","promise","contacts","defaults","quality","reliability","transparency","links"],"type":"object"},"TrustRuntimeDuration":{"additionalProperties":false,"properties":{"available":{"description":"Whether the minimum fresh-outcome duration sample exists.","type":"boolean"},"low_sample":{"type":"boolean"},"minimum_sample_count":{"const":10,"type":"integer"},"p50":{"oneOf":[{"minimum":0,"type":"integer"},{"type":"null"}]},"p95":{"oneOf":[{"minimum":0,"type":"integer"},{"type":"null"}]},"p99":{"oneOf":[{"minimum":0,"type":"integer"},{"type":"null"}]},"sample_count":{"description":"Fresh outcomes represented by the latest disclosed attempt-batch snapshot; null until at least 10 outcomes are available in a disclosed snapshot.","oneOf":[{"minimum":10,"type":"integer"},{"type":"null"}]},"sample_limit":{"const":4096,"description":"Maximum recent fresh-outcome durations retained in the in-memory percentile sample.","type":"integer"}},"required":["available","sample_count","minimum_sample_count","low_sample","p50","p95","p99","sample_limit"],"type":"object"},"TrustRuntimeQuality":{"additionalProperties":false,"properties":{"available":{"description":"Whether at least one privacy-safe 10-attempt disclosure batch is available.","type":"boolean"},"cache_responses_excluded":{"const":true,"type":"boolean"},"completion_ratio":{"description":"Completed fresh executions divided by fresh attempts in the latest disclosed batch snapshot, or null before the first batch. Dispatch and worker-contract failures remain in the denominator.","oneOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"duration_ms":{"$ref":"#/components/schemas/TrustRuntimeDuration"},"failure_ratio":{"description":"Fresh dispatch and worker-contract failures divided by fresh attempts in the latest disclosed batch snapshot, or null before the first batch.","oneOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"low_sample":{"description":"True until the first 10-attempt disclosure batch is complete.","type":"boolean"},"minimum_sample_count":{"const":10,"type":"integer"},"not_security_score":{"const":true,"type":"boolean"},"note":{"description":"Explicit process-reset, fixed disclosure-batch, and bounded-percentile semantics.","type":"string"},"partial_ratio":{"description":"Partial fresh executions divided by fresh attempts in the latest disclosed batch snapshot, or null before the first batch.","oneOf":[{"maximum":1,"minimum":0,"type":"number"},{"type":"null"}]},"privacy":{"$ref":"#/components/schemas/TrustRuntimeQualityPrivacy"},"sample_count":{"description":"Fresh worker execution attempts included in the latest completed 10-attempt disclosure batch; null before the first batch. Cache responses are excluded.","oneOf":[{"minimum":10,"multipleOf":10,"type":"integer"},{"type":"null"}]},"scope":{"const":"since_process_start","description":"Process-local counters reset whenever the deployed API process restarts; the public snapshot advances in completed 10-attempt batches.","type":"string"},"source":{"const":"runtime_metrics","type":"string"}},"required":["source","scope","available","sample_count","minimum_sample_count","low_sample","completion_ratio","partial_ratio","failure_ratio","cache_responses_excluded","duration_ms","not_security_score","privacy","note"],"type":"object"},"TrustRuntimeQualityPrivacy":{"additionalProperties":false,"properties":{"aggregate_only":{"const":true,"type":"boolean"},"endpoint_metrics_included":{"const":false,"type":"boolean"},"ephemeral_scan_rows_persisted":{"const":false,"type":"boolean"},"port_details_included":{"const":false,"type":"boolean"},"source_ips_included":{"const":false,"type":"boolean"},"targets_included":{"const":false,"type":"boolean"}},"required":["aggregate_only","ephemeral_scan_rows_persisted","source_ips_included","targets_included","port_details_included","endpoint_metrics_included"],"type":"object"},"TrustRuntimeReliability":{"additionalProperties":false,"properties":{"not_availability_sla":{"const":true,"type":"boolean"},"note":{"description":"Current-process and worker registry-state caveat.","type":"string"},"scope":{"const":"current_process","type":"string"},"source":{"const":"runtime_status","type":"string"},"uptime_seconds":{"minimum":0,"type":"integer"},"worker_pool":{"$ref":"#/components/schemas/TrustRuntimeWorkerPool"}},"required":["source","scope","uptime_seconds","worker_pool","not_availability_sla","note"],"type":"object"},"TrustRuntimeWorkerPool":{"additionalProperties":false,"properties":{"ready":{"description":"Workers in registry ready state; this does not assert spare concurrency or compatibility with every profile.","minimum":0,"type":"integer"},"registered":{"description":"Workers currently present in the registry heartbeat snapshot.","minimum":0,"type":"integer"}},"required":["registered","ready"],"type":"object"},"TrustSafetyScoreboard":{"properties":{"exposure_ratio_24h":{"maximum":1,"minimum":0,"type":"number"},"exposure_ratio_delta_pp":{"type":"number"},"exposure_ratio_prev_24h":{"maximum":1,"minimum":0,"type":"number"},"new_exposure_sessions_24h":{"minimum":0,"type":"integer"},"resolved_exposure_sessions_24h":{"minimum":0,"type":"integer"},"scans_24h":{"minimum":0,"type":"integer"},"scans_prev_24h":{"minimum":0,"type":"integer"},"scans_with_open_ports_24h":{"minimum":0,"type":"integer"},"scans_with_open_ports_prev_24h":{"minimum":0,"type":"integer"},"trend":{"enum":["improving","stable","worsening"],"type":"string"}},"required":["scans_24h","scans_with_open_ports_24h","exposure_ratio_24h","scans_prev_24h","scans_with_open_ports_prev_24h","exposure_ratio_prev_24h","exposure_ratio_delta_pp","new_exposure_sessions_24h","resolved_exposure_sessions_24h","trend"],"type":"object"},"TrustTransparencyAggregateExposure":{"additionalProperties":false,"properties":{"exposure_ratio_24h":{"description":"Aggregate share of recent scans that observed at least one open port.","maximum":1,"minimum":0,"type":"number"},"exposure_ratio_delta_pp":{"description":"Percentage-point delta versus the previous 24-hour aggregate window.","type":"number"},"new_exposure_sessions_24h":{"minimum":0,"type":"integer"},"not_security_score":{"const":true,"description":"This aggregate is not a host safety verdict or vulnerability score.","type":"boolean"},"resolved_exposure_sessions_24h":{"minimum":0,"type":"integer"},"scans_24h":{"minimum":0,"type":"integer"},"scans_with_open_ports_24h":{"minimum":0,"type":"integer"},"trend":{"enum":["improving","stable","worsening"],"type":"string"}},"required":["scans_24h","scans_with_open_ports_24h","exposure_ratio_24h","exposure_ratio_delta_pp","new_exposure_sessions_24h","resolved_exposure_sessions_24h","trend","not_security_score"],"type":"object"},"TrustTransparencyPrivacy":{"additionalProperties":false,"properties":{"aggregate_only":{"const":true,"type":"boolean"},"ephemeral_scan_rows_persisted":{"const":false,"description":"Default ephemeral scan rows are not persisted for `/trust`; explicit saved-result events may be retained only for their configured retention window.","type":"boolean"},"publication_policy":{"$ref":"#/components/schemas/TrustTransparencyPublicationPolicy"},"raw_scan_rows_exposed":{"const":false,"type":"boolean"},"source_ips_exposed":{"const":false,"type":"boolean"},"targets_exposed":{"const":false,"type":"boolean"},"top_open_port_details_exposed":{"const":false,"description":"/trust exposes only the count of top-open-port groups that pass publication thresholds, not the port rows themselves.","type":"boolean"}},"required":["aggregate_only","ephemeral_scan_rows_persisted","source_ips_exposed","targets_exposed","raw_scan_rows_exposed","top_open_port_details_exposed","publication_policy"],"type":"object"},"TrustTransparencyPublicationPolicy":{"additionalProperties":false,"properties":{"minimum_open_observations":{"const":10,"description":"Minimum open-port observations required before an aggregate port group may count as publishable.","type":"integer"},"minimum_unique_source_ips":{"const":5,"description":"Minimum distinct observed source IPs required before an aggregate port group may count as publishable.","type":"integer"},"publication_delay_hours":{"const":24,"description":"Aggregate port groups are delayed before publication.","type":"integer"},"small_groups_suppressed":{"const":true,"description":"Groups below the publication thresholds remain suppressed and are folded into aggregate-only exposure weather.","type":"boolean"}},"required":["minimum_unique_source_ips","minimum_open_observations","publication_delay_hours","small_groups_suppressed"],"type":"object"},"TrustTransparencySample":{"additionalProperties":false,"properties":{"low_sample":{"description":"True when the explicit saved-result window is too small for agents to treat aggregate trend as strong evidence.","type":"boolean"},"minimum_scan_events_24h":{"description":"Minimum recent explicit saved-result events before trend context is no longer low-sample.","minimum":1,"type":"integer"},"minimum_unique_source_ips_24h":{"description":"Minimum recent unique request-source IPs before trend context is no longer low-sample.","minimum":1,"type":"integer"},"note":{"description":"Human-readable caveat for interpreting aggregate trend context.","type":"string"},"scan_count_24h":{"minimum":0,"type":"integer"},"unique_source_ips_24h":{"minimum":0,"type":"integer"}},"required":["low_sample","scan_count_24h","unique_source_ips_24h","minimum_scan_events_24h","minimum_unique_source_ips_24h","note"],"type":"object"},"TrustTransparencySummary":{"additionalProperties":false,"properties":{"aggregate_exposure":{"$ref":"#/components/schemas/TrustTransparencyAggregateExposure"},"available":{"description":"Whether persisted aggregate transparency is currently available.","type":"boolean"},"data_scope":{"description":"Scope represented by historical transparency counters. `explicit_saved_results_only` means only explicitly saved-result scan events are counted; default ephemeral scans are excluded.","enum":["runtime_only","explicit_saved_results_only"],"type":"string"},"ephemeral_scans_included":{"const":false,"description":"Default ephemeral scans are not included in historical `/trust` counters.","type":"boolean"},"last_24h":{"description":"Aggregate scan quality counters for the last 24 hours, or null while unavailable.","oneOf":[{"$ref":"#/components/schemas/TrustWindowStats"},{"type":"null"}]},"note":{"description":"Human-readable availability note.","type":"string"},"privacy":{"$ref":"#/components/schemas/TrustTransparencyPrivacy"},"sample":{"$ref":"#/components/schemas/TrustTransparencySample"},"source":{"description":"Snapshot source. `runtime_only` means historical aggregate storage is disabled or unavailable.","enum":["runtime_only","postgres_scan_events"],"type":"string"},"top_open_ports_24h_count":{"description":"Count of top-open-port aggregate groups that pass publication thresholds; port details are intentionally omitted from `/trust`.","minimum":0,"type":"integer"}},"required":["source","available","data_scope","ephemeral_scans_included","note","last_24h","sample","aggregate_exposure","top_open_ports_24h_count","privacy"],"type":"object"},"TrustWindowStats":{"properties":{"avg_open_ports":{"minimum":0,"type":"number"},"completion_ratio":{"maximum":1,"minimum":0,"type":"number"},"duration_p50_ms":{"minimum":0,"type":"integer"},"duration_p95_ms":{"minimum":0,"type":"integer"},"partial_ratio":{"maximum":1,"minimum":0,"type":"number"},"scan_count":{"minimum":0,"type":"integer"},"unique_source_ips":{"minimum":0,"type":"integer"}},"required":["scan_count","unique_source_ips","completion_ratio","partial_ratio","avg_open_ports","duration_p50_ms","duration_p95_ms"],"type":"object"},"VisiblePortsCommunity":{"properties":{"available":{"type":"boolean"},"benchmark":{"$ref":"#/components/schemas/VisiblePortsCommunityBenchmark"},"exposure_weather":{"type":"string"},"matched_open_ports":{"items":{"$ref":"#/components/schemas/VisiblePortsCommunityPort"},"type":"array"},"note":{"type":"string"},"safety":{"properties":{"aggregate_only":{"const":true,"type":"boolean"},"arbitrary_targets_exposed":{"const":false,"type":"boolean"},"purpose":{"const":"defensive_prioritization","type":"string"},"source_ips_exposed":{"const":false,"type":"boolean"}},"required":["aggregate_only","source_ips_exposed","arbitrary_targets_exposed","purpose"],"type":"object"},"sample":{"$ref":"#/components/schemas/VisiblePortsCommunitySample"},"source":{"enum":["runtime_only","postgres_scan_events"],"type":"string"},"summary":{"type":"string"},"top_open_ports_24h":{"description":"Aggregate defensive top-open-port context only; never includes source IPs, targets, hostnames, CIDRs, banners, or payloads.","items":{"$ref":"#/components/schemas/VisiblePortsCommunityPort"},"type":"array"}},"required":["source","available","summary","exposure_weather","sample","benchmark","matched_open_ports","top_open_ports_24h","safety","note"],"type":"object"},"VisiblePortsCommunityBenchmark":{"description":"Aggregate-only comparison between the current request-source result and IfPort Commons exposure weather.","properties":{"aggregate_exposure_ratio_24h":{"minimum":0,"type":"number"},"aggregate_exposure_trend":{"type":"string"},"comparison":{"enum":["no_aggregate_baseline","current_result_has_no_open_ports","current_open_ports_match_commons","current_open_ports_not_seen_in_commons","current_open_ports_partially_seen_in_commons"],"type":"string"},"current_open_port_count":{"minimum":0,"type":"integer"},"current_open_ports_new_to_commons":{"minimum":0,"type":"integer"},"current_open_ports_seen_in_commons":{"minimum":0,"type":"integer"},"headline":{"type":"string"},"operator_meaning":{"type":"string"},"safety_note":{"type":"string"},"status":{"enum":["community_unavailable","clean_baseline_below_aggregate","current_exposure_seen_in_commons","current_exposure_uncommon_in_commons","current_exposure_mixed_commons_signal"],"type":"string"},"support_reason":{"type":"string"}},"required":["status","headline","comparison","operator_meaning","current_open_port_count","current_open_ports_seen_in_commons","current_open_ports_new_to_commons","aggregate_exposure_ratio_24h","aggregate_exposure_trend","support_reason","safety_note"],"type":"object"},"VisiblePortsCommunityPort":{"properties":{"common_service":{"nullable":true,"type":"string"},"open_observations_24h":{"minimum":0,"type":"integer"},"open_observations_7d":{"minimum":0,"type":"integer"},"port":{"maximum":65535,"minimum":1,"type":"integer"},"relevance":{"enum":["current_open_and_seen_in_commons","current_open_not_seen_in_commons","community_top_open_port"],"type":"string"},"risk_hint":{"type":"string"},"unique_source_count_24h":{"minimum":0,"type":"integer"},"unique_source_count_7d":{"minimum":0,"type":"integer"}},"required":["port","common_service","open_observations_24h","unique_source_count_24h","open_observations_7d","unique_source_count_7d","risk_hint","relevance"],"type":"object"},"VisiblePortsCommunitySample":{"additionalProperties":false,"properties":{"low_sample":{"description":"True when the explicit saved-result window is too small for agents to treat aggregate community context as strong evidence.","type":"boolean"},"minimum_scan_events_24h":{"description":"Minimum recent explicit saved-result events before community context is no longer low-sample.","minimum":1,"type":"integer"},"minimum_unique_source_ips_24h":{"description":"Minimum recent unique request-source IPs before community context is no longer low-sample.","minimum":1,"type":"integer"},"note":{"description":"Human-readable caveat for interpreting aggregate community context.","type":"string"},"scan_count_24h":{"minimum":0,"type":"integer"},"unique_source_ips_24h":{"minimum":0,"type":"integer"}},"required":["low_sample","scan_count_24h","unique_source_ips_24h","minimum_scan_events_24h","minimum_unique_source_ips_24h","note"],"type":"object"},"VisiblePortsResponse":{"deprecated":true,"description":"Legacy rich response schema retained only for compatibility projections such as explicit `view=full`. Canonical scan endpoints (`/json`, `/report`, and `/results`) use CoreVisiblePortsResponse or JsonExpandedVisiblePortsResponse instead; new clients should not build against this legacy presentation/support-heavy schema.\n","properties":{"accuracy":{"properties":{"confidence":{"enum":["high","medium","low"],"type":"string"},"next_steps":{"items":{"type":"string"},"type":"array"},"observed_ip_scope":{"enum":["public","private","cgnat","loopback","link_local","unique_local","documentation","benchmark","invalid_or_unknown"],"type":"string"},"reasons":{"items":{"type":"string"},"type":"array"},"representation":{"enum":["direct_request_path","verified_edge_header","trusted_edge_header","translated_or_proxy_path","unknown_path"],"type":"string"}},"required":["representation","confidence","observed_ip_scope","reasons","next_steps"],"type":"object"},"agent_handoff":{"properties":{"confidence_note":{"type":"string"},"intent":{"const":"explain_result_to_user","type":"string"},"likely_issue":{"enum":["translated_or_proxy_path","expected_ports_not_visible","unexpected_public_exposure","no_public_ports_detected","clean_but_proxy_path","critical_remote_access_exposure","data_service_exposure","policy_mismatch_exposure","intent_validation_required"],"type":"string"},"next_action":{"type":"string"},"next_command":{"type":"string"},"safety_boundary":{"type":"string"},"summary":{"type":"string"},"support_note":{"type":"string"},"user_message":{"type":"string"}},"required":["intent","likely_issue","summary","user_message","next_action","next_command","confidence_note","safety_boundary","support_note"],"type":"object"},"assessment":{"properties":{"coverage":{"$ref":"#/components/schemas/ScanCoverage"},"policy_verdict":{"enum":["pass","warn","fail","not_evaluated"],"type":"string"},"recommended_actions":{"items":{"type":"string"},"type":"array"},"scan_result":{"enum":["no_open_ports_detected","open_ports_detected"],"type":"string"},"security_assurance":{"enum":["not_assessed"],"type":"string"},"summary":{"type":"string"}},"required":["scan_result","policy_verdict","coverage","security_assurance","summary","recommended_actions"],"type":"object"},"automation":{"properties":{"baseline_policy":{"description":"Commit-ready request-source baseline policy generated from the current scan. It is an exposure gate artifact, not an arbitrary target permission.","properties":{"arbitrary_targets_allowed":{"const":false,"type":"boolean"},"expected_open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"fingerprint_sha256":{"type":"string"},"gate_url":{"type":"string"},"generated_by":{"const":"ifport.io","type":"string"},"note":{"type":"string"},"observed_source_ip":{"type":"string"},"profile":{"type":"string"},"request_source_only":{"const":true,"type":"boolean"},"snapshot_id":{"type":"string"},"speed":{"description":"Speed used by `baseline_policy.gate_url`, not necessarily the speed of the scan that generated this automation block.","type":"string"},"target_scope":{"const":"request_source_ip_only","type":"string"},"version":{"const":"ifport_policy.v1","type":"string"}},"required":["version","generated_by","target_scope","observed_source_ip","profile","speed","expected_open_ports","gate_url","snapshot_id","fingerprint_sha256","request_source_only","arbitrary_targets_allowed","note"],"type":"object"},"bash_gate_snippet":{"type":"string"},"expected_open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"gate_baseline_url":{"type":"string"},"gate_now_url":{"type":"string"},"github_actions_step":{"type":"string"},"gitlab_ci_job":{"type":"string"}},"required":["gate_now_url","gate_baseline_url","expected_open_ports","baseline_policy","bash_gate_snippet","github_actions_step","gitlab_ci_job"],"type":"object"},"brief":{"description":"Canonical one-request result+concept block for humans, CLIs, UIs, and LLM agents.","properties":{"answer":{"description":"Short user-facing explanation of the scan result.","type":"string"},"artifacts":{"description":"Direct operator artifacts returned with the one-request brief. Scan-backed artifact URLs preserve the current scan scope, policy, and speed.","items":{"properties":{"name":{"enum":["gate","evidence","report","network_path"],"type":"string"},"purpose":{"type":"string"},"url":{"format":"uri","type":"string"},"use_when":{"type":"string"}},"required":["name","url","purpose","use_when"],"type":"object"},"type":"array"},"concept":{"type":"string"},"confidence":{"type":"string"},"evidence":{"properties":{"fingerprint_sha256":{"type":"string"},"snapshot_id":{"type":"string"},"verify_url":{"format":"uri","type":"string"}},"required":["snapshot_id","fingerprint_sha256","verify_url"],"type":"object"},"headline":{"type":"string"},"next_action":{"type":"string"},"next_command":{"type":"string"},"observed_source_ip":{"type":"string"},"open_ports":{"description":"Human-readable open TCP port list, or none.","type":"string"},"reason_code":{"type":"string"},"safety_boundary":{"type":"string"},"support":{"properties":{"donate_ready":{"description":"True when a payment provider link is configured behind /donate.","type":"boolean"},"donate_url":{"format":"uri","type":"string"},"impact_summary":{"type":"string"},"monthly_gap_usd":{"minimum":0,"type":"integer"},"nearest_unlock_id":{"type":"string"},"nearest_unlock_outcome":{"type":"string"},"next_support_action":{"type":"string"},"provider_status":{"enum":["configured","provider_missing"],"type":"string"},"reason":{"type":"string"}},"required":["reason","donate_url","donate_ready","provider_status","monthly_gap_usd","nearest_unlock_id","nearest_unlock_outcome","impact_summary","next_support_action"],"type":"object"},"target_scope":{"const":"request_source_ip_only","type":"string"},"verdict":{"enum":["allow","review","block"],"type":"string"}},"required":["headline","answer","verdict","reason_code","target_scope","observed_source_ip","open_ports","next_action","next_command","confidence","concept","safety_boundary","evidence","artifacts","support"],"type":"object"},"cache":{"properties":{"hit":{"type":"boolean"},"ttl_seconds":{"type":"integer"}},"required":["hit","ttl_seconds"],"type":"object"},"community":{"$ref":"#/components/schemas/VisiblePortsCommunity"},"decision":{"properties":{"actions":{"items":{"type":"string"},"type":"array"},"evidence":{"properties":{"accuracy_confidence":{"enum":["high","medium","low"],"type":"string"},"coverage":{"$ref":"#/components/schemas/ScanCoverage"},"policy_verdict":{"enum":["pass","warn","fail","not_evaluated"],"type":"string"},"scan_result":{"enum":["no_open_ports_detected","open_ports_detected"],"type":"string"},"security_assurance":{"enum":["not_assessed"],"type":"string"},"triage_severity":{"enum":["info","medium","high","critical"],"type":"string"}},"required":["policy_verdict","scan_result","coverage","security_assurance","triage_severity","accuracy_confidence"],"type":"object"},"message":{"type":"string"},"reason_code":{"enum":["low_confidence_observation_path","unexpected_public_exposure","manual_intent_validation_required","partial_scan","policy_and_exposure_within_expected_bounds"],"type":"string"},"status":{"enum":["allow","review","block"],"type":"string"}},"required":["status","reason_code","message","actions","evidence"],"type":"object"},"drift":{"$ref":"#/components/schemas/ScanDrift"},"intent":{"description":"Request-source-only scenario preset and interpretation. Intent presets never accept ip, host, target, CIDR, domain lists, payloads, credentials, or third-party infrastructure.","properties":{"applied_policy":{"type":"string"},"applied_profile":{"type":"string"},"expected_outcome":{"type":"string"},"matching_open_ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"name":{"enum":["general-exposure","web-deploy","remote-access","database-exposure"],"type":"string"},"next_action":{"type":"string"},"not_seen_ports_of_interest":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"policy_from_intent":{"type":"boolean"},"ports_of_interest":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"preset_applied":{"type":"boolean"},"profile_from_intent":{"type":"boolean"},"provided":{"type":"boolean"},"purpose":{"type":"string"},"reason_code":{"type":"string"},"runbook":{"description":"Scenario-specific operator runbook for the request-source-only intent verdict.","properties":{"copy_paste_markdown":{"type":"string"},"decision_rule":{"type":"string"},"likely_causes":{"items":{"type":"string"},"type":"array"},"remediation_steps":{"items":{"type":"string"},"type":"array"},"title":{"type":"string"},"verify_commands":{"items":{"type":"string"},"type":"array"}},"required":["title","decision_rule","likely_causes","verify_commands","remediation_steps","copy_paste_markdown"],"type":"object"},"safety_boundary":{"type":"string"},"summary":{"type":"string"},"verdict":{"enum":["pass","review","fail"],"type":"string"}},"required":["name","provided","preset_applied","purpose","expected_outcome","applied_profile","applied_policy","profile_from_intent","policy_from_intent","ports_of_interest","matching_open_ports","not_seen_ports_of_interest","verdict","reason_code","summary","next_action","runbook","safety_boundary"],"type":"object"},"limitations":{"items":{"type":"string"},"type":"array"},"links":{"properties":{"action_plan":{"type":"string"},"docs":{"type":"string"},"donate":{"type":"string"},"evidence":{"type":"string"},"network_path":{"type":"string"},"openapi":{"type":"string"},"status":{"type":"string"},"support":{"type":"string"},"trust":{"type":"string"}},"required":["docs","support","openapi","action_plan","evidence","network_path","status","trust","donate"],"type":"object"},"network":{"properties":{"ip_source":{"enum":["transport_remote_ip","x_real_ip_trusted_proxy","cf_connecting_ip_trusted_proxy","x_forwarded_for_trusted_proxy"],"type":"string"},"observed_source_ip":{"type":"string"},"transport_remote_ip":{"nullable":true,"type":"string"}},"required":["observed_source_ip","ip_source"],"type":"object"},"observed_source_ip":{"type":"string"},"open_ports":{"items":{"$ref":"#/components/schemas/OpenPort"},"type":"array"},"operator_card":{"description":"Compact one-request operator card intended for direct user handoff, tickets, CLIs, and LLM agents.","properties":{"answer":{"type":"string"},"automation":{"items":{"type":"string"},"type":"array"},"boundary":{"type":"string"},"card_version":{"const":"operator_card.v1","type":"string"},"concept":{"type":"string"},"confidence":{"type":"string"},"copy_paste_markdown":{"type":"string"},"do_now":{"items":{"type":"string"},"type":"array"},"proof":{"items":{"type":"string"},"type":"array"},"severity":{"enum":["info","medium","high","critical"],"type":"string"},"support_prompt":{"type":"string"},"title":{"type":"string"},"verdict":{"enum":["allow","review","block"],"type":"string"}},"required":["card_version","title","verdict","severity","answer","concept","boundary","confidence","do_now","proof","automation","support_prompt","copy_paste_markdown"],"type":"object"},"partial":{"type":"boolean"},"policy":{"properties":{"allowed_open_ports":{"items":{"type":"integer"},"type":"array"},"missing_expected_ports":{"items":{"type":"integer"},"type":"array"},"name":{"type":"string"},"note":{"type":"string"},"unexpected_open_ports":{"items":{"type":"integer"},"type":"array"},"verdict":{"enum":["pass","warn","fail","not_evaluated"],"type":"string"}},"required":["name","verdict","allowed_open_ports","unexpected_open_ports","missing_expected_ports","note"],"type":"object"},"project":{"properties":{"category":{"const":"request_source_port_visibility","type":"string"},"default_check":{"type":"string"},"defensive_boundary":{"type":"string"},"name":{"const":"ifport.io","type":"string"},"one_request_promise":{"type":"string"},"outputs":{"items":{"properties":{"name":{"enum":["report","evidence","network_path","status","trust"],"type":"string"},"purpose":{"type":"string"},"url":{"format":"uri","type":"string"}},"required":["name","url","purpose"],"type":"object"},"type":"array"},"useful_for":{"items":{"type":"string"},"type":"array"}},"required":["name","category","one_request_promise","defensive_boundary","default_check","useful_for","outputs"],"type":"object"},"receipt":{"description":"Operator value receipt explaining what this one request produced and why support is justified.","properties":{"copy_paste_markdown":{"type":"string"},"estimated_minutes_saved":{"minimum":0,"type":"integer"},"operator_next_step":{"type":"string"},"receipt_id":{"type":"string"},"support_case":{"type":"string"},"support_this_check_url":{"description":"Per-result sponsor link that carries receipt_id and snapshot_id context only.","format":"uri","type":"string"},"title":{"type":"string"},"value_drivers":{"items":{"type":"string"},"type":"array"},"value_summary":{"type":"string"}},"required":["receipt_id","title","value_summary","estimated_minutes_saved","value_drivers","operator_next_step","support_case","support_this_check_url","copy_paste_markdown"],"type":"object"},"results":{"properties":{"closed":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"errors":{"items":{"$ref":"#/components/schemas/PortError"},"type":"array"},"filtered_or_timeout":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"open":{"items":{"$ref":"#/components/schemas/OpenPort"},"type":"array"}},"required":["open","closed","filtered_or_timeout","errors"],"type":"object"},"scan":{"properties":{"duration_ms":{"minimum":0,"type":"integer"},"global_timeout_ms":{"minimum":1,"type":"integer"},"per_port_timeout_ms":{"minimum":1,"type":"integer"},"ports_checked":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"type":"array"},"profile":{"enum":["default","web","databases","mail","top1000","custom"],"type":"string"},"scan_id":{"description":"Internal scan UUID for tracing this request-source-only scan. Default scans do not create public result permalinks; use `?persist=true` or `POST /results` and read `persistence.result_token` for an explicit saved result.","format":"uuid","type":"string"},"speed":{"enum":["fast","balanced","deep"],"type":"string"},"started_at":{"format":"date-time","type":"string"},"type":{"description":"Public MVP scan strategy. The worker tries TCP SYN for public IPv4 targets when raw sockets are available and falls back to TCP connect where SYN is not available or not appropriate.","enum":["tcp_syn_or_connect"],"type":"string"}},"required":["scan_id","started_at","type","profile","speed","duration_ms","per_port_timeout_ms","global_timeout_ms","ports_checked"],"type":"object"},"schema_version":{"const":"1.0","type":"string"},"service":{"const":"ifport.io","type":"string"},"share":{"properties":{"badge_markdown":{"type":"string"},"evidence_url":{"format":"uri","type":"string"},"markdown":{"description":"Copy-paste Markdown summary for tickets, chats, README notes, or incident records.","type":"string"},"readme_markdown":{"description":"Short README/support snippet with badge, evidence, and support action.","type":"string"},"report_card_markdown":{"description":"Compact result card for tickets, incident records, README notes, and agent handoff.","type":"string"},"result_card_svg_url":{"description":"Embeddable read-only SVG card when `persistence.persisted=true`; empty for default ephemeral scans.","type":"string"},"result_evidence_url":{"description":"Read-only persisted evidence pack when `persistence.persisted=true`; empty for default ephemeral scans.","type":"string"},"result_summary":{"type":"string"},"result_url":{"description":"Read-only permalink when `persistence.persisted=true`; empty for default ephemeral scans.","type":"string"},"social_text":{"description":"Short share text that preserves the request-source-only safety boundary.","type":"string"},"support_callout":{"type":"string"},"support_this_check_url":{"description":"Per-result sponsor action URL carrying only receipt and snapshot attribution context.","format":"uri","type":"string"},"ticket_title":{"description":"Ready issue/incident title for the current request-source result.","type":"string"},"title":{"type":"string"},"verify_url":{"format":"uri","type":"string"}},"required":["title","result_summary","result_url","result_card_svg_url","result_evidence_url","markdown","report_card_markdown","ticket_title","readme_markdown","social_text","badge_markdown","verify_url","evidence_url","support_this_check_url","support_callout"],"type":"object"},"snapshot":{"properties":{"fingerprint_sha256":{"type":"string"},"signature":{"nullable":true,"properties":{"algorithm":{"const":"ed25519","type":"string"},"canonicalization":{"const":"rfc8785_jcs(ifport_signature_envelope_v1)","type":"string"},"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"key_id":{"type":"string"},"payload_sha256":{"pattern":"^[0-9a-f]{64}$","type":"string"},"public_key_hex":{"pattern":"^[0-9a-f]{64}$","type":"string"},"signature_base":{"const":"ifport_signature_envelope_v1","type":"string"},"signature_hex":{"pattern":"^[0-9a-f]{128}$","type":"string"},"signed_payload":{"const":"scan_snapshot_fingerprint_source_v1","type":"string"}},"required":["algorithm","key_id","public_key_hex","signature_hex","signed_payload","signature_base","canonicalization","payload_sha256","created_at","expires_at"],"type":"object"},"snapshot_id":{"type":"string"},"verification":{"minimum":0,"type":"string"},"version":{"type":"string"}},"required":["version","snapshot_id","fingerprint_sha256","verification"],"type":"object"},"support":{"properties":{"contribution_examples":{"items":{"type":"string"},"type":"array"},"coverage_ratio":{"maximum":1,"minimum":0,"type":"number"},"donate_links":{"items":{"$ref":"#/components/schemas/SupportLink"},"type":"array"},"donate_ready":{"description":"True when a payment provider link is configured behind /donate.","type":"boolean"},"donate_url":{"format":"uri","type":"string"},"free_check":{"type":"boolean"},"monthly_covered_usd":{"minimum":0,"type":"integer"},"monthly_gap_usd":{"minimum":0,"type":"integer"},"monthly_target_usd":{"minimum":0,"type":"integer"},"nearest_unlock":{"nullable":true,"properties":{"id":{"type":"string"},"operator_outcome":{"type":"string"},"remaining_usd":{"minimum":0,"type":"integer"}},"required":["id","remaining_usd","operator_outcome"],"type":"object"},"next_support_action":{"type":"string"},"provider_setup":{"$ref":"#/components/schemas/SupportProviderSetup"},"provider_status":{"enum":["configured","provider_missing"],"type":"string"},"support_intent":{"$ref":"#/components/schemas/SupportIntent"},"why_support":{"type":"string"}},"required":["free_check","donate_ready","provider_status","monthly_target_usd","monthly_covered_usd","monthly_gap_usd","coverage_ratio","donate_url","donate_links","provider_setup","why_support","next_support_action","nearest_unlock","contribution_examples","support_intent"],"type":"object"},"support_proof":{"description":"Support-boundary proof pack tying the scan result, evidence, value receipt, and support ask together without implying paid scan access.","properties":{"copy_paste_markdown":{"type":"string"},"donate_url":{"format":"uri","type":"string"},"donation_ask":{"type":"string"},"estimated_minutes_saved":{"minimum":0,"type":"integer"},"evidence":{"items":{"type":"string"},"type":"array"},"nearest_unlock_id":{"type":"string"},"nearest_unlock_outcome":{"type":"string"},"no_paid_access_note":{"type":"string"},"proof_version":{"const":"support_proof.v1","type":"string"},"provider_status":{"enum":["provider_missing","configured"],"type":"string"},"summary":{"type":"string"},"support_this_check_url":{"description":"Per-result sponsor link mirrored from the value receipt; not a paid scan access link.","format":"uri","type":"string"},"title":{"type":"string"},"value_receipt_id":{"type":"string"}},"required":["proof_version","title","summary","evidence","value_receipt_id","estimated_minutes_saved","donation_ask","donate_url","support_this_check_url","provider_status","nearest_unlock_id","nearest_unlock_outcome","no_paid_access_note","copy_paste_markdown"],"type":"object"},"target":{"properties":{"ip":{"type":"string"},"type":{"const":"request_source_ip","type":"string"}},"required":["type","ip"],"type":"object"},"triage":{"properties":{"first_15_min_steps":{"items":{"type":"string"},"type":"array"},"headline":{"type":"string"},"scenario":{"enum":["no_public_ports_detected","clean_but_proxy_path","critical_remote_access_exposure","data_service_exposure","policy_mismatch_exposure","expected_ports_not_visible","intent_validation_required"],"type":"string"},"severity":{"enum":["info","medium","high","critical"],"type":"string"},"verify_commands":{"items":{"type":"string"},"type":"array"}},"required":["scenario","severity","headline","first_15_min_steps","verify_commands"],"type":"object"}},"required":["schema_version","service","observed_source_ip","target","intent","brief","operator_card","scan","results","open_ports","partial","cache","assessment","policy","accuracy","triage","decision","agent_handoff","automation","project","support","community","share","receipt","support_proof","snapshot","drift","limitations","links"],"type":"object"}}},"info":{"summary":"Like what is my IP, but for visible TCP ports","title":"ifport.io request-source port visibility API","version":"0.1.0","x-ifport-build-id":"2026.07.13.1248","x-ifport-release-sha":"a5577414420e"},"openapi":"3.1.0","paths":{"/":{"get":{"description":"Browser-like requests get a no-scan HTML landing page. CLI/bot requests get a compact request-source Markdown scan brief. Deterministic scan modes are available with `?format=json`, `?format=markdown`, and `?format=plain` so agents do not need to rely on heuristics. Use `/report` for the human Markdown/HTML report. Use `?format=json` for the stable core machine contract; `view=core` is accepted as an explicit spelling and `view=min` is a deprecated alias for the same core JSON projection. Use `expand` only with JSON output to request explicit non-funding blocks.\n","operationId":"getRootEntry","parameters":[{"$ref":"#/components/parameters/RootFormat"},{"$ref":"#/components/parameters/RootView"},{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/Policy"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CoreVisiblePortsResponse"},{"$ref":"#/components/schemas/JsonExpandedVisiblePortsResponse"}]}},"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"Root scan result in negotiated representation","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid scan request or non-public observed request-source path; use /network-path to inspect attribution","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Root entrypoint for the public request-source service","tags":["Core"]}},"/.well-known/funding.json":{"get":{"deprecated":true,"description":"This well-known funding manifest alias is hidden until there is real demand.","operationId":"getWellKnownFundingManifestGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /support","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired funding manifest alias","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"support"}},"/.well-known/funding.yml":{"get":{"deprecated":true,"description":"This well-known funding YAML alias is hidden until there is real demand.","operationId":"getWellKnownFundingYmlGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /support","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired FUNDING.yml starter alias","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"support"}},"/.well-known/openapi.json":{"get":{"operationId":"getWellKnownOpenApi","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"OpenAPI JSON","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get this OpenAPI document","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headWellKnownOpenApi","responses":{"200":{"description":"OpenAPI JSON","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /.well-known/openapi.json","tags":["Discovery"]}},"/.well-known/security.txt":{"get":{"description":"RFC 9116-style security contact metadata for ifport.io.\n","operationId":"getWellKnownSecurityTxt","responses":{"200":{"content":{"text/plain":{"schema":{"type":"string"}}},"description":"Security contact metadata","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl3600"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get security.txt","tags":["Support"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headWellKnownSecurityTxt","responses":{"200":{"description":"Security contact metadata","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl3600"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /.well-known/security.txt","tags":["Support"]}},"/about":{"get":{"description":"Static no-scan description of the request-source-only service boundary.\n","operationId":"getAbout","responses":{"200":{"content":{"text/markdown":{"schema":{"type":"string"}}},"description":"Product boundary Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Static product boundary","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headAbout","responses":{"200":{"description":"Product boundary Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /about","tags":["Discovery"]}},"/acceptable-use":{"get":{"description":"Short acceptable-use policy for the defensive request-source-only service boundary: no forwarding-header spoofing, no rate-limit evasion, no arbitrary third-party targets, no vulnerability assessment claim, no reliance on unchecked ports, and no abuse of persisted results.\n","operationId":"getAcceptableUsePolicy","responses":{"200":{"content":{"text/markdown":{"schema":{"type":"string"}}},"description":"Acceptable-use policy Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get acceptable-use policy","tags":["Support"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headAcceptableUsePolicy","responses":{"200":{"description":"Acceptable-use policy Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /acceptable-use","tags":["Support"]}},"/action-plan":{"get":{"deprecated":true,"description":"Compatibility alias for older action-plan clients. Query string is preserved and redirected to `/report`; use `/report` for human remediation context, `/gate` for CI policy checks, `/evidence` for portable proof, and `/network-path` for request-source attribution. The alias itself does not run a scan.","operationId":"getActionPlanAlias","responses":{"308":{"description":"Permanent redirect to /report","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/report","schema":{"const":"/report","type":"string"}}}}},"summary":"Deprecated remediation alias merged into /report","tags":["CI"],"x-ifport-decision":"redirect","x-ifport-owner":"report"}},"/automation-pack":{"get":{"deprecated":true,"description":"The public automation-pack generator is hidden from the canonical surface. Use `/gate` for CI policy checks, `/report` for human context, and `/network-path` for request-source attribution.","operationId":"getAutomationPackGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /gate","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired automation-pack surface","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"gate"}},"/automation-pack.tar.gz":{"get":{"deprecated":true,"description":"The downloadable public automation-pack archive is hidden from the canonical surface. Use `/gate` for CI policy checks, `/report` for human context, and `/network-path` for request-source attribution.","operationId":"getAutomationPackArchiveGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /gate","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired automation-pack archive surface","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"gate"}},"/badge.svg":{"get":{"deprecated":true,"description":"This public badge surface is hidden until there is real demand.","operationId":"getSupportBadgeGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /support","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired support badge","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"support"}},"/check":{"get":{"operationId":"checkVisiblePortsMarkdown","parameters":[{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"},{"$ref":"#/components/parameters/Policy"}],"responses":{"200":{"description":"Markdown port visibility report","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request, unsupported request-source boundary parameter, profile or ports, or non-public observed source; use /network-path to inspect attribution","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service unavailable or explicit saved-result creation disabled by operator safe mode","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Get Markdown TCP port visibility for the request source IP","tags":["Core"]}},"/docs":{"get":{"description":"Backend-generated public docs landing page. HAProxy allowlists this route and proxies it to `ifport-public-api`; it must not serve a static shadow copy for `/docs`.\n","operationId":"getDocs","responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"Public documentation page","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl60"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get documentation without running a scan","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headDocs","responses":{"200":{"description":"Public documentation page","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl60"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /docs","tags":["Discovery"]}},"/donate":{"get":{"description":"Redirects to the configured primary support provider when available for browser/HTML clients. Without a configured provider, renders a short no-scan support page. `format=json` returns a minimal provider-pending/status payload with public contacts and coverage categories only. Payment never changes scan access, speed, request-source scan scope, rate limits, or prioritization.\n","operationId":"getDonate","parameters":[{"description":"Force JSON or HTML support action output when no provider redirect is used.","in":"query","name":"format","required":false,"schema":{"enum":["json","html"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"build_id":{"minLength":1,"type":"string"},"contacts":{"additionalProperties":false,"properties":{"abuse":{"const":"abuse@ifport.io","type":"string"},"security":{"const":"security@ifport.io","type":"string"}},"required":["security","abuse"],"type":"object"},"donate_ready":{"type":"boolean"},"links":{"additionalProperties":false,"properties":{"support":{"const":"https://ifport.io/support","type":"string"}},"required":["support"],"type":"object"},"message":{"type":"string"},"monthly_infrastructure_target_usd":{"minimum":0,"type":"integer"},"release_sha":{"minLength":1,"type":"string"},"service":{"const":"ifport.io","type":"string"},"stable_donate_url":{"const":"https://ifport.io/donate","type":"string"},"status":{"enum":["ready_to_donate","provider_pending"],"type":"string"},"support_helps_cover":{"example":["hosting","monitoring","bandwidth","abuse protection"],"items":{"type":"string"},"maxItems":4,"minItems":4,"type":"array"}},"required":["status","service","build_id","release_sha","stable_donate_url","donate_ready","message","monthly_infrastructure_target_usd","support_helps_cover","contacts","links"],"type":"object"}},"text/html":{"schema":{"type":"string"}}},"description":"Support action page or minimal JSON context when no provider redirect is used","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}},"302":{"description":"Redirect to configured donation provider","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"Location":{"schema":{"format":"uri","type":"string"}},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid donate response format","headers":{"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Stable donation action","tags":["Support"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headDonate","parameters":[{"description":"Force JSON or HTML support action output when no provider redirect is used.","in":"query","name":"format","required":false,"schema":{"enum":["json","html"],"type":"string"}}],"responses":{"200":{"description":"Support action page or minimal JSON context when no provider redirect is used","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}},"302":{"description":"Redirect to configured donation provider","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"Location":{"schema":{"format":"uri","type":"string"}},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}},"400":{"description":"Invalid donate response format","headers":{"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"HEAD metadata for /donate","tags":["Support"]}},"/evidence":{"get":{"description":"Runs the same request-source-only scan and returns a portable evidence pack: compact verdict fields, snapshot fingerprint/signature data, `/verify` payload, copy-paste Markdown, Slack text, and commands for CI gates and signed verification. `format=markdown` or `Accept: text/markdown` returns the copy-paste Markdown directly.\n","operationId":"getEvidence","parameters":[{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"},{"$ref":"#/components/parameters/Policy"},{"$ref":"#/components/parameters/EvidenceFormat"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvidenceResponse"}},"text/markdown":{"schema":{"type":"string"}}},"description":"Portable evidence response","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request, unsupported request-source boundary parameter, format, profile, policy or ports, or non-public observed source; use /network-path to inspect attribution","headers":{"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Portable request-source scan proof for tickets, CI, and incident review","tags":["Evidence"]}},"/funding.json":{"get":{"deprecated":true,"description":"This public funding manifest is hidden until there is real demand. Use `/support` for support boundaries and contacts.","operationId":"getFundingManifestGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /support","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired funding manifest","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"support"}},"/funding.yml":{"get":{"deprecated":true,"description":"This public funding YAML surface is hidden until there is real demand.","operationId":"getFundingYmlGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /support","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired FUNDING.yml starter","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"support"}},"/gate":{"get":{"description":"Returns a compact gate verdict. Complete pass/not_evaluated states use HTTP 200 with `status=ok`. Warn/fail states and incomplete scans use HTTP 409 with `status=blocked`, `reason_code`, the same verdict/snapshot fields, compact `action.next_command` follow-up, and a compatible `error.code=policy_gate_failed` object for older clients. New clients should use `reason_code` to distinguish bounded-policy failures. If the observed request-source path is non-public, no scan runs and the endpoint returns HTTP 400 `invalid_request` with `/network-path` guidance instead of a gate verdict.\n","operationId":"gateVisiblePorts","parameters":[{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"},{"$ref":"#/components/parameters/Policy"},{"$ref":"#/components/parameters/IncludeFullResult"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GateResponse"}}},"description":"Gate passed after all selected ports completed","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request, unsupported request-source boundary parameter, profile, policy or ports, or non-public observed source; use /network-path to inspect attribution","headers":{"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GateResponse"}}},"description":"Gate failed, warning state, or incomplete scan","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"CI/CD gate verdict for request-source visibility","tags":["CI"]}},"/impact":{"get":{"deprecated":true,"description":"Compatibility alias for the former impact ledger. Use `/status` for service state and `/trust` for public trust metadata plus bounded aggregate-only transparency.","operationId":"getImpactAlias","responses":{"308":{"description":"Permanent redirect to /status","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/status","schema":{"const":"/status","type":"string"}}}}},"summary":"Deprecated alias for /status","tags":["Operations"],"x-ifport-decision":"redirect","x-ifport-owner":"status"}},"/incident-bundle":{"get":{"deprecated":true,"description":"Compatibility alias for older incident-bundle clients. Query string is preserved and redirected to `/report`; use `/report` for human context, `/gate` for CI policy checks, `/evidence` for portable proof, and `/network-path` for request-source attribution.","operationId":"getIncidentBundleAlias","responses":{"308":{"description":"Permanent redirect to /report","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/report","schema":{"const":"/report","type":"string"}}}}},"summary":"Deprecated alias merged into /report","tags":["Deprecated"],"x-ifport-decision":"redirect","x-ifport-owner":"report"}},"/json":{"get":{"description":"Returns open TCP ports for the observed request-source path that contacted ifport.io. This does not necessarily identify the end user's local machine if the request passes through NAT, VPN, proxy, CI/CD, cloud runtime, or LLM sandbox.\n","operationId":"getVisiblePortsForRequestSource","parameters":[{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"},{"$ref":"#/components/parameters/Policy"},{"$ref":"#/components/parameters/View"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Persist"}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CoreVisiblePortsResponse"},{"$ref":"#/components/schemas/JsonExpandedVisiblePortsResponse"}]}}},"description":"Structured port visibility report","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request, unsupported request-source boundary parameter, profile or ports, or non-public observed source; use /network-path to inspect attribution","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Get TCP ports visible from the observed request-source path","tags":["Core"]}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","responses":{"200":{"content":{"text/plain":{"schema":{"type":"string"}}},"description":"Plain text LLM guidance","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get compact LLM/agent usage guidance","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headLlmsTxt","responses":{"200":{"description":"Plain text LLM guidance","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /llms.txt","tags":["Discovery"]}},"/markdown":{"get":{"deprecated":true,"description":"Compatibility alias for `/check`. New clients should use `/check`. Query string is preserved in the redirect; the alias itself does not run a scan.","operationId":"checkVisiblePortsMarkdownAlias","responses":{"308":{"description":"Permanent redirect to /check","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/check","schema":{"const":"/check","type":"string"}}}}},"summary":"Deprecated alias for /check","tags":["Deprecated"],"x-ifport-decision":"redirect","x-ifport-owner":"check"}},"/mcp":{"get":{"description":"The canonical remote MCP endpoint is `POST /mcp`. This deployment does not offer a server-initiated SSE stream on GET, so Streamable HTTP GET returns 405 as allowed by the MCP 2025-11-25 transport.\n","operationId":"getMcpStreamableHttpSse","responses":{"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"SSE stream not offered; use POST for MCP JSON-RPC","headers":{"Allow":{"description":"Only POST is supported for the public MCP endpoint.","schema":{"const":"POST","type":"string"}},"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Streamable HTTP MCP GET is not offered","tags":["Discovery"]},"post":{"description":"Supports minimal MCP JSON-RPC methods: `initialize`, `notifications/initialized`, `tools/list`, and `tools/call` for the `check_request_source_ports` tool. Tool calls scan only the observed request-source IP of the MCP client/platform and reject arbitrary target arguments. Streamable HTTP clients should send `Accept: application/json, text/event-stream` and `MCP-Protocol-Version: 2025-11-25`. Browser-based clients must send a trusted `Origin`; send `MCP-Session-Id` only if a future initialize response returns one. Call `initialize` first, send `notifications/initialized`, then use `tools/list` to retrieve the tool `inputSchema` and `outputSchema`. `tools/call` accepts `profile`, `ports`, `speed`, `intent`, `policy`, and `expect_open`. Partial scans return a JSON-RPC tool result with `isError=true` while retaining the unchanged core partial scan in `structuredContent`; clients should inspect completion accounting and retry the same bounded scope. Complete scans keep `isError=false` even when the raw bounded policy verdict is `warn` or `fail`.\n","operationId":"postMcpJsonRpc","parameters":[{"description":"MCP Streamable HTTP clients must accept JSON and SSE media types.","in":"header","name":"Accept","required":true,"schema":{"example":"application/json, text/event-stream","type":"string"}},{"description":"If present, must be the supported MCP protocol version.","in":"header","name":"MCP-Protocol-Version","required":false,"schema":{"const":"2025-11-25","type":"string"}},{"description":"Required for browser-based MCP clients and validated by the server.","in":"header","name":"Origin","required":false,"schema":{"example":"https://ifport.io","type":"string"}},{"description":"Reserved for session-aware clients; send only if initialize returns it.","in":"header","name":"MCP-Session-Id","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"checkRequestSourcePorts":{"summary":"Check the observed request-source path only","value":{"id":3,"jsonrpc":"2.0","method":"tools/call","params":{"arguments":{"profile":"default","speed":"balanced"},"name":"check_request_source_ports"}}},"initialize":{"summary":"Initialize the IfPort MCP session","value":{"id":1,"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{},"clientInfo":{"name":"ifport-openapi-example","version":"0.1.0"},"protocolVersion":"2025-11-25"}}},"initialized":{"summary":"Send initialized notification","value":{"jsonrpc":"2.0","method":"notifications/initialized"}},"toolsList":{"summary":"Retrieve the request-source tool schema","value":{"id":2,"jsonrpc":"2.0","method":"tools/list"}}},"schema":{"oneOf":[{"additionalProperties":false,"properties":{"id":{"oneOf":[{"type":"integer"},{"type":"string"}]},"jsonrpc":{"const":"2.0","type":"string"},"method":{"const":"initialize","type":"string"},"params":{"additionalProperties":true,"properties":{"capabilities":{"additionalProperties":true,"type":"object"},"clientInfo":{"additionalProperties":true,"type":"object"},"protocolVersion":{"const":"2025-11-25","type":"string"}},"required":["protocolVersion","capabilities","clientInfo"],"type":"object"}},"required":["jsonrpc","id","method","params"],"title":"MCP initialize request","type":"object"},{"additionalProperties":false,"properties":{"jsonrpc":{"const":"2.0","type":"string"},"method":{"const":"notifications/initialized","type":"string"}},"required":["jsonrpc","method"],"title":"MCP initialized notification","type":"object"},{"additionalProperties":false,"properties":{"id":{"oneOf":[{"type":"integer"},{"type":"string"}]},"jsonrpc":{"const":"2.0","type":"string"},"method":{"const":"tools/list","type":"string"},"params":{"additionalProperties":false,"type":"object"}},"required":["jsonrpc","id","method"],"title":"MCP tools/list request","type":"object"},{"additionalProperties":false,"properties":{"id":{"oneOf":[{"type":"integer"},{"type":"string"}]},"jsonrpc":{"const":"2.0","type":"string"},"method":{"const":"tools/call","type":"string"},"params":{"additionalProperties":false,"properties":{"arguments":{"additionalProperties":false,"description":"Request-source-only tool arguments. Do not send `ip`, `host`, `target`, `cidr`, `range`, `url`, `domain`, source-IP search, or aliases such as `hostname` or `target_ip`.\n","properties":{"expect_open":{"oneOf":[{"type":"string"},{"items":{"maximum":65535,"minimum":1,"type":"integer"},"maxItems":50,"type":"array","uniqueItems":true}]},"intent":{"enum":["general-exposure","web-deploy","remote-access","database-exposure"],"type":"string"},"policy":{"default":"strict","enum":["strict","web","remote-admin","database-private","none"],"type":"string"},"ports":{"items":{"maximum":65535,"minimum":1,"type":"integer"},"maxItems":50,"type":"array","uniqueItems":true},"profile":{"default":"default","enum":["default","web","databases","mail","top1000"],"type":"string"},"speed":{"default":"balanced","enum":["fast","balanced","deep"],"type":"string"}},"type":"object"},"name":{"const":"check_request_source_ports","type":"string"}},"required":["name","arguments"],"type":"object"}},"required":["jsonrpc","id","method","params"],"title":"MCP tools/call request","type":"object"}]}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"MCP JSON-RPC response. Complete tools/call scans use isError=false; partial scans use isError=true and retain the core partial scan in structuredContent. Tool errors include structuredContent.error. Scan results and tool errors include X-Request-Id matching structuredContent; JSON-RPC errors include the same value in error.data.request_id.","headers":{"Cache-Control":{"$ref":"#/components/headers/McpCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"202":{"description":"MCP initialized notification accepted","headers":{"Cache-Control":{"$ref":"#/components/headers/McpCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcErrorResponse"}}},"description":"Malformed JSON, invalid JSON-RPC request, or unsupported MCP protocol version","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcErrorResponse"}}},"description":"Browser Origin is not allowed for the public MCP endpoint","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"406":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcErrorResponse"}}},"description":"Accept header does not allow both MCP JSON and SSE media types","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Invoke the IfPort Streamable HTTP MCP JSON-RPC endpoint","tags":["Discovery"]}},"/mission":{"get":{"deprecated":true,"description":"Compatibility alias for the former expanded mission bundle. Use `/about` for the static product boundary, `/report` for human scan context, `/gate` for CI policy checks, `/evidence` for portable proof, and `/network-path` for request-source attribution.","operationId":"getMissionAlias","responses":{"308":{"description":"Permanent redirect to /about","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/about","schema":{"const":"/about","type":"string"}}}}},"summary":"Deprecated alias merged into /about","tags":["Deprecated"],"x-ifport-decision":"redirect","x-ifport-owner":"about"}},"/network-path":{"get":{"description":"Returns how ifport.io resolved observed_source_ip from trusted proxy headers and transport address. Useful to debug proxy/NAT paths when scan confidence is low.\n","operationId":"getNetworkPath","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NetworkPathResponse"}}},"description":"Source attribution diagnostics","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Explain request source-IP attribution path without running a scan","tags":["Diagnostics"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headNetworkPath","responses":{"200":{"description":"Source attribution diagnostics","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /network-path","tags":["Diagnostics"]}},"/one-shot":{"get":{"deprecated":true,"description":"Compatibility alias for older one-shot clients. Query string is preserved and redirected to `/report`.","operationId":"getOneShotAlias","responses":{"308":{"description":"Permanent redirect to /report","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/report","schema":{"const":"/report","type":"string"}}}}},"summary":"Deprecated alias merged into /report","tags":["Deprecated"],"x-ifport-decision":"redirect","x-ifport-owner":"report"}},"/openapi-compat.json":{"get":{"description":"Compatibility contract that keeps deprecated aliases, migration routes, and explicit compatibility projections out of the compact agent contract. Retired response schemas for routes that now redirect or return endpoint_gone are intentionally omitted.","operationId":"getCompatOpenApiJson","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"Compatibility OpenAPI contract","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get the IfPort compatibility OpenAPI contract","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headCompatOpenApiJson","responses":{"200":{"description":"Compatibility OpenAPI contract","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /openapi-compat.json","tags":["Discovery"]}},"/openapi-extended.json":{"get":{"deprecated":true,"description":"Compatibility alias for the former extended OpenAPI document. New clients that need migration details should use `/openapi-compat.json`; default clients should use `/openapi.json`.","operationId":"getExtendedOpenApiAlias","responses":{"308":{"description":"Permanent redirect to /openapi-compat.json","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/openapi-compat.json","schema":{"const":"/openapi-compat.json","type":"string"}}}}},"summary":"Deprecated alias for /openapi-compat.json","tags":["Discovery"],"x-ifport-decision":"redirect","x-ifport-owner":"docs"}},"/openapi.json":{"get":{"operationId":"getOpenApi","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"OpenAPI JSON","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get this OpenAPI document","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headOpenApi","responses":{"200":{"description":"OpenAPI JSON","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /openapi.json","tags":["Discovery"]}},"/plain":{"get":{"operationId":"getVisiblePortsPlain","parameters":[{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"},{"$ref":"#/components/parameters/Policy"}],"responses":{"200":{"content":{"text/plain":{"schema":{"description":"Body contains only newline-separated decimal open TCP port numbers. An empty body means no open ports were observed in the selected bounded scan scope. This response never includes comments, URLs, support copy, report text, or explanations.\n","type":"string"}}},"description":"Newline-separated open TCP ports","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request, unsupported request-source boundary parameter, profile, policy or ports, or non-public observed source; use /network-path to inspect attribution","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Get only open TCP ports for shell scripts","tags":["Core"]}},"/playbook":{"get":{"deprecated":true,"description":"Compatibility alias for the former operator playbook. Use `/docs`.","operationId":"getPlaybookAlias","responses":{"308":{"description":"Permanent redirect to /docs","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/docs","schema":{"const":"/docs","type":"string"}}}}},"summary":"Deprecated alias for /docs","tags":["Deprecated"],"x-ifport-decision":"redirect","x-ifport-owner":"docs"}},"/privacy":{"get":{"description":"Explains default ephemeral scans, explicit saved results, TTL, noindex/noarchive headers, deletion, and whether the observed source IP is stored in clear text for saved results.\n","operationId":"getPrivacyPolicy","responses":{"200":{"content":{"text/markdown":{"schema":{"type":"string"}}},"description":"Privacy policy Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get public privacy policy","tags":["Support"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headPrivacyPolicy","responses":{"200":{"description":"Privacy policy Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /privacy","tags":["Support"]}},"/readiness":{"get":{"deprecated":true,"description":"Compatibility alias for the former readiness surface. Use `/status` for no-scan service status.","operationId":"getReadinessAlias","responses":{"308":{"description":"Permanent redirect to /status","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/status","schema":{"const":"/status","type":"string"}}}}},"summary":"Deprecated alias for /status","tags":["Operations"],"x-ifport-decision":"redirect","x-ifport-owner":"status"}},"/report":{"get":{"description":"Returns the canonical human report for the request-source scan. Browser clients can request HTML, CLI clients can request Markdown, and `format=json` returns the expanded non-funding scan payload for compatibility.\n","operationId":"getVisiblePortsReport","parameters":[{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"},{"$ref":"#/components/parameters/Policy"},{"$ref":"#/components/parameters/ReportFormat"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonExpandedVisiblePortsResponse"}},"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}},"description":"Human report or expanded JSON response","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request, unsupported request-source boundary parameter, profile or ports, or non-public observed source; use /network-path to inspect attribution","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Service unavailable or explicit saved-result creation disabled by operator safe mode","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Get a human request-source scan report","tags":["Core"]}},"/result/{token}":{"delete":{"description":"Deletes an explicitly saved result. Send the delete token as `Authorization: Bearer ifp_...` or, for clients that cannot set Authorization, `X-IfPort-Delete-Token: ifp_...`. Query-string `delete_token` is intentionally not accepted because URLs are commonly written to access logs, shell history, and Referer headers.\n","operationId":"deletePersistedScanResult","parameters":[{"$ref":"#/components/parameters/ResultToken"},{"$ref":"#/components/parameters/DeleteAuthorization"},{"$ref":"#/components/parameters/DeleteTokenHeader"}],"responses":{"204":{"description":"Saved result deleted"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid result_token or missing, malformed, conflicting, or query-string delete token","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Saved result not found or delete token did not match","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Result store unavailable","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Delete an explicitly saved result by result token and header delete token","tags":["Persistence"]},"get":{"description":"Returns a previously saved request-source-only scan result. Saved results are created only with `?persist=true` or `POST /results`, use a random result token rather than the internal scan UUID, expire by retention policy, and send `X-Robots-Tag: noindex, noarchive`. Opening this permalink does not run a new scan and does not support lookup by IP, host, target, CIDR, range, domain, or source-IP search.\n","operationId":"getPersistedScanResult","parameters":[{"$ref":"#/components/parameters/ResultToken"},{"$ref":"#/components/parameters/ResultFormat"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersistedResultResponse"}},"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}},"description":"Persisted scan result"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid result_token or format","headers":{"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Persisted result not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Result store unavailable, or SVG card generation disabled by operator safe mode","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Read an explicitly saved request-source scan result by result token","tags":["Persistence"]}},"/result/{token}.svg":{"get":{"description":"Returns a read-only SVG card for a previously persisted request-source-only scan result. Opening this card does not run a new scan and does not support lookup by IP, host, target, CIDR, range, domain, or source-IP search.\n","operationId":"getPersistedScanResultCardSvg","parameters":[{"$ref":"#/components/parameters/ResultToken"}],"responses":{"200":{"content":{"image/svg+xml":{"schema":{"type":"string"}}},"description":"Embeddable persisted result SVG card"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid result_token","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Persisted result not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Result store unavailable","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Get an embeddable SVG card for a persisted request-source result","tags":["Persistence"]}},"/result/{token}/evidence":{"get":{"description":"Returns a read-only persisted evidence pack derived from stored `scan_events.raw_payload` for a previous explicit request-source-only saved result. Opening this endpoint does not run a scan and does not support lookup by IP, host, target, CIDR, range, domain, or source-IP search.\n","operationId":"getPersistedScanEvidence","parameters":[{"$ref":"#/components/parameters/ResultToken"},{"$ref":"#/components/parameters/EvidenceFormat"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersistedEvidenceResponse"}},"text/markdown":{"schema":{"type":"string"}}},"description":"Persisted scan evidence"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid result_token or format","headers":{"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Persisted result not found","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Result store unavailable","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Read a persisted evidence pack by result token","tags":["Persistence"]}},"/results":{"post":{"description":"Runs a request-source-only scan and saves the result explicitly. This is equivalent to adding `?persist=true` to a scan endpoint. The response includes `persistence.result_token`, `persistence.result_url`, `persistence.delete_token`, `persistence.expires_at`, and retention metadata. Saved result pages and evidence send `X-Robots-Tag: noindex, noarchive`.\n","operationId":"createPersistedScanResult","parameters":[{"$ref":"#/components/parameters/Profile"},{"$ref":"#/components/parameters/Intent"},{"$ref":"#/components/parameters/Ports"},{"$ref":"#/components/parameters/ExpectOpen"},{"$ref":"#/components/parameters/Speed"},{"$ref":"#/components/parameters/Policy"},{"$ref":"#/components/parameters/View"},{"$ref":"#/components/parameters/Expand"}],"responses":{"201":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CoreVisiblePortsResponse"},{"$ref":"#/components/schemas/JsonExpandedVisiblePortsResponse"}]}}},"description":"Saved scan result created","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"Location":{"description":"Saved result URL","schema":{"format":"uri","type":"string"}},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid request, unsupported request-source boundary parameter, profile or ports, or non-public observed source; use /network-path to inspect attribution","headers":{"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"Vary":{"$ref":"#/components/headers/ScanVary"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Explicitly create a saved request-source scan result","tags":["Persistence"]}},"/robots.txt":{"get":{"description":"Returns no-scan crawler metadata for the public request-source-only product surface and points crawlers to `/sitemap.xml`.\n","operationId":"getRobotsTxt","responses":{"200":{"content":{"text/plain":{"schema":{"type":"string"}}},"description":"Robots text","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl3600"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get crawler discovery policy","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headRobotsTxt","responses":{"200":{"description":"Robots text","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl3600"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /robots.txt","tags":["Discovery"]}},"/security":{"get":{"description":"Returns the no-scan public security policy, reporting contact, abuse contact, disclosure fields, and request-source-only boundary.\n","operationId":"getSecurityPolicy","responses":{"200":{"content":{"text/markdown":{"schema":{"type":"string"}}},"description":"Security policy Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get public security policy","tags":["Support"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headSecurityPolicy","responses":{"200":{"description":"Security policy Markdown","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /security","tags":["Support"]}},"/sitemap.xml":{"get":{"description":"Returns no-scan sitemap metadata for the public IfPort product, documentation, support, and machine-readable surfaces.\n","operationId":"getSitemapXml","responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"XML sitemap","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl3600"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get public sitemap","tags":["Discovery"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headSitemapXml","responses":{"200":{"description":"XML sitemap","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl3600"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /sitemap.xml","tags":["Discovery"]}},"/sponsor-kit":{"get":{"deprecated":true,"description":"This public surface is hidden until there is real demand. Use `/support` for contacts and support boundary.","operationId":"getSponsorKitGone","responses":{"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Gone; use /support","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Retired sponsor-kit surface","tags":["Deprecated"],"x-ifport-decision":"gone","x-ifport-owner":"support"}},"/status":{"get":{"operationId":"getStatus","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}},"description":"Service status","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get service status without running a scan","tags":["Operations"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headStatus","responses":{"200":{"description":"Service status","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /status","tags":["Operations"]}},"/support":{"get":{"operationId":"getSupport","responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"Support and transparency page","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Support ifport.io infrastructure","tags":["Support"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headSupport","responses":{"200":{"description":"Support and transparency page","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /support","tags":["Support"]}},"/terms":{"get":{"deprecated":true,"description":"Compatibility alias for the former terms page. New clients should use `/acceptable-use` for the request-source-only acceptable-use policy.","operationId":"getTermsAlias","responses":{"308":{"description":"Permanent redirect to /acceptable-use","headers":{"Cache-Control":{"$ref":"#/components/headers/RedirectCacheControl"},"Location":{"example":"/acceptable-use","schema":{"const":"/acceptable-use","type":"string"}}}}},"summary":"Deprecated alias for /acceptable-use","tags":["Support"],"x-ifport-decision":"redirect","x-ifport-owner":"policy"}},"/trust":{"get":{"description":"Returns live defensive-boundary, quality, and reliability signals for ifport.io without running a scan.\n","operationId":"getTrust","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrustResponse"}}},"description":"Public trust status","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get public trust and reliability signals","tags":["Operations"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headTrust","responses":{"200":{"description":"Public trust status","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /trust","tags":["Operations"]}},"/verify":{"get":{"operationId":"getVerifyInfo","responses":{"200":{"description":"Verification endpoint metadata","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get snapshot verification endpoint metadata","tags":["Evidence"]},"post":{"description":"Validates snapshot evidence fields produced by ifport.io scan responses. Recomputes the canonical fingerprint source hash and checks snapshot_id derivation. If a signature block is provided, verifies Ed25519 signature integrity using the public keys published by `/verify/keys`.\n","operationId":"postVerifySnapshot","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotVerifyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotVerifyResponse"}}},"description":"Verification result","headers":{"Cache-Control":{"$ref":"#/components/headers/ScanCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Malformed or invalid verification payload; returns ErrorResponse with invalid_request or a more specific validation code","headers":{"Cache-Control":{"$ref":"#/components/headers/StatusCacheControl"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"},"X-Request-Id":{"$ref":"#/components/headers/RequestId"}}}},"summary":"Verify snapshot fingerprint and optional signature","tags":["Evidence"]}},"/verify/keys":{"get":{"description":"Returns the Ed25519 public keys and canonical signature-envelope serialization metadata needed to verify signed snapshot evidence outside the ifport.io runtime. Private signing material is never returned.\n","operationId":"getVerifyKeys","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotVerifyKeysResponse"}}},"description":"Public snapshot verification keys","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"Get current and previous public keys for snapshot verification","tags":["Evidence"]},"head":{"description":"Link-checker friendly metadata probe for this no-scan retrievability endpoint. It returns the same status and cache/build headers as GET without a response body.","operationId":"headVerifyKeys","responses":{"200":{"description":"Public snapshot verification keys","headers":{"Cache-Control":{"$ref":"#/components/headers/PublicCacheControl300"},"ETag":{"$ref":"#/components/headers/BuildEtag"},"X-IfPort-Build":{"$ref":"#/components/headers/BuildId"}}}},"summary":"HEAD metadata for /verify/keys","tags":["Evidence"]}}},"servers":[{"url":"https://ifport.io"}],"tags":[{"description":"Request-source scan outputs.","name":"Core"},{"description":"Source attribution and network-path diagnostics.","name":"Diagnostics"},{"description":"Release gates and remediation workflow outputs.","name":"CI"},{"description":"Portable proof and signature verification.","name":"Evidence"},{"description":"Explicit saved-result lifecycle.","name":"Persistence"},{"description":"Machine-readable discovery documents and docs.","name":"Discovery"},{"description":"Operational status and trust metadata.","name":"Operations"},{"description":"Support, contacts, security policy, and donation action.","name":"Support"},{"description":"Compatibility aliases and retired surfaces in the extended contract only.","name":"Deprecated"}]}