{"components":{"responses":{"BadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Invalid IPv4 address/CIDR, too many items, or requested range too large."},"ServiceUnavailable":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"MongoDB or another required service is unavailable."},"TooManyRequests":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Rate limit exceeded. Public deployments may return this from the reverse proxy before the Flask app handles the request."}},"schemas":{"ErrorResponse":{"properties":{"errors":{"type":"string"},"mongo":{"type":"string"},"status":{"type":"string"}},"type":"object"},"FeedHit":{"properties":{"category":{"type":["string","null"]},"current_status":{"enum":["present","absent"],"type":"string"},"entries":{"type":["string","null"]},"feed_last_synced_at":{"type":["string","null"]},"feed_name":{"type":"string"},"feed_sync_status":{"type":["string","null"]},"first_seen":{"type":["string","null"]},"last_added":{"type":["string","null"]},"last_removed":{"type":["string","null"]},"list_source_url":{"type":["string","null"]},"maintainer":{"type":["string","null"]},"maintainer_url":{"type":["string","null"]},"match_type":{"enum":["ip","cidr",null],"type":["string","null"]},"matched_entry":{"description":"Original feed entry that matched the query, for example 64.62.156.0/24.","type":["string","null"]},"matched_ip":{"description":"Requested IP when a single-IP query matched this feed entry.","type":["string","null"]},"matched_prefix_length":{"type":["integer","null"]},"matched_range_end":{"type":["string","null"]},"matched_range_start":{"type":["string","null"]},"matched_source_file_date":{"type":["string","null"]},"source_age_days":{"type":["integer","null"]},"source_file_date":{"type":["string","null"]},"source_is_stale":{"type":"boolean"},"timeline":{"items":{"$ref":"#/components/schemas/TimelineEvent"},"type":"array"}},"type":"object"},"SearchResponse":{"properties":{"blacklisted_count":{"type":"integer"},"currently_blacklisted_count":{"type":"integer"},"range_records_count":{"description":"CIDR/range index document count when hybrid range search is active.","type":["integer","null"]},"records_count":{"type":"integer"},"request_time":{"type":"string"},"requested_count":{"type":"integer"},"results":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array"},"storage_mode":{"enum":["expanded_ip","hybrid",null],"type":["string","null"]},"truncated":{"type":"boolean"}},"required":["request_time","records_count","requested_count","blacklisted_count","currently_blacklisted_count","results","truncated"],"type":"object"},"SearchResult":{"properties":{"categories":{"items":{"type":"string"},"type":"array"},"currently_blacklisted":{"type":"boolean"},"first_seen":{"type":["string","null"]},"hits":{"items":{"$ref":"#/components/schemas/FeedHit"},"type":"array"},"hits_count":{"type":"integer"},"ip":{"type":"string"},"last_added":{"type":["string","null"]}},"type":"object"},"TimelineEvent":{"properties":{"added":{"type":"string"},"removed":{"type":["string","null"]}},"type":"object"}}},"info":{"description":"Search reviewed FireHOL-derived IPv4 blocklist feeds. Public search defaults to current hits from fresh feeds only. Historical and stale-feed results are opt-in.","title":"Sernate FireHOL Search IP API","version":"2.0.0-preview","x-sernate-compatibility":"Documented public response fields are stable for the current endpoints. New fields may be added. Existing documented fields are not removed or renamed without a versioned replacement or deprecation period."},"openapi":"3.1.0","paths":{"/docs":{"get":{"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"HTML documentation"}},"summary":"Human-readable API documentation","tags":["Docs"]}},"/openapi.json":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"OpenAPI document"}},"summary":"OpenAPI specification","tags":["Docs"]}},"/search":{"post":{"description":"Accepts a comma-separated text body. Maximum items and total requested IPs are enforced by the API.","parameters":[{"description":"When true, only currently present hits are returned. Set false to include historical hits whose current_status is absent.","in":"query","name":"current_only","required":false,"schema":{"default":true,"type":"boolean"}},{"description":"When false, feed sources older than max_feed_age_days are hidden. Set true for investigation/history views that include stale feeds.","in":"query","name":"include_stale","required":false,"schema":{"default":false,"type":"boolean"}}],"requestBody":{"content":{"text/html":{"schema":{"example":"8.8.8.8,1.1.1.1","type":"string"}},"text/plain":{"schema":{"example":"8.8.8.8,1.1.1.1","type":"string"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}},"description":"Search result"},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Search multiple IPv4 addresses or CIDR ranges","tags":["Search"]}},"/search/ip":{"get":{"description":"v1-compatible search endpoint. IPv4 only. CIDR ranges are limited server-side to protect the API and database.","parameters":[{"description":"IPv4 address or allowed IPv4 CIDR range.","in":"query","name":"v","required":true,"schema":{"examples":["1.15.51.236","203.0.113.0/24"],"type":"string"}},{"description":"When true, only currently present hits are returned. Set false to include historical hits whose current_status is absent.","in":"query","name":"current_only","required":false,"schema":{"default":true,"type":"boolean"}},{"description":"When false, feed sources older than max_feed_age_days are hidden. Set true for investigation/history views that include stale feeds.","in":"query","name":"include_stale","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"examples":{"currentBlocklistHit":{"summary":"Current blocklist hit","value":{"blacklisted_count":1,"currently_blacklisted_count":1,"requested_count":1,"results":[{"categories":["abuse"],"currently_blacklisted":true,"hits":[{"current_status":"present","feed_name":"example_feed","maintainer":"Example Maintainer","source_age_days":0,"source_is_stale":false}],"hits_count":2,"ip":"223.204.250.203"}],"truncated":false}},"historyInvestigation":{"description":"Use current_only=false and include_stale=true to inspect old or removed listings. These should not be treated as current blocking evidence without manual review.","summary":"Historical/stale investigation","value":{"blacklisted_count":1,"currently_blacklisted_count":1,"requested_count":1,"results":[{"currently_blacklisted":true,"hits":[{"current_status":"absent","feed_name":"myip","last_removed":"Fri, 20 Mar 2026 12:20:52 GMT","source_is_stale":false}],"hits_count":1,"ip":"8.8.8.8"}],"truncated":false}}},"schema":{"$ref":"#/components/schemas/SearchResponse"}}},"description":"Search result"},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Search one IPv4 address or CIDR range","tags":["Search"]}}},"servers":[{"description":"Production","url":"https://blocklist.sernate.com"},{"description":"Local container","url":"http://127.0.0.1:8000"}],"tags":[{"description":"IP and CIDR lookup endpoints","name":"Search"},{"description":"API documentation","name":"Docs"}],"x-sernate-limits":{"default_current_only":true,"default_include_stale":false,"ipv4_only":true,"max_cidr_prefix_length":32,"max_feed_age_days":366,"max_request_body_bytes":16384,"max_requested_ips":65536,"max_search_items":100,"min_cidr_prefix_length":16,"search_result_limit":500}}
