ScanMalware REST API Documentation

Complete API reference for integrating website security scanning into your applications

Getting Started

The ScanMalware API provides programmatic access to URL security scanning capabilities. All endpoints return JSON responses and use standard HTTP status codes.

🌐 Base URL

https://scanmalware.com

🚀 Quick Example

curl -X POST "https://scanmalware.com/api/v1/scan" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
📖 Full Documentation Details

Rate Limits

Requests are rate limited per IP address. Sending an API key raises your limit substantially, so authenticate any automated or high-volume use.

  • Anonymous: 600 requests/minute to /api/ (60/minute for hash search pages)
  • With an API key: 3000 requests/minute

Short bursts above these rates are allowed before anything is rejected. Exceeding the limit returns 429 Too Many Requests with a JSON body and a Retry-After header — wait for that many seconds and retry. Create a key on your account page and send it as the X-API-Key header.

Pagination

All search and listing endpoints support pagination to prevent database overload and improve performance. Pagination is implemented using page and limit parameters.

Paginated endpoints include:

  • /api/v1/recent - Recent scans
  • /api/v1/search - Text search
  • /api/v1/search/asn/{asn_number} - ASN search
  • /api/v1/search/favicon/{hash_value} - Favicon hash search
  • /api/v1/search/screenshot/{hash_type}/{hash_value} - Screenshot hash search
  • /api/v1/search/fuzzy/{hash_type} - Fuzzy hash search
  • /api/v1/search/similar - Similar scans search

All paginated responses include a pagination object:

"pagination": {
  "page": 1,          // Current page number
  "limit": 20,        // Items per page
  "total_items": 272, // Total number of items
  "total_pages": 14,  // Total number of pages
  "has_next": true,   // Whether there's a next page
  "has_prev": false   // Whether there's a previous page
}

Error Handling

The API uses conventional HTTP response codes to indicate success or failure. Error responses include a JSON object with error details.

{
  "error": "Invalid URL provided",
  "code": 400,
  "details": "The URL must be a valid HTTP or HTTPS URL"
}

Finding subdomains of a domain

Several endpoints return hostnames beneath a domain, but they answer different questions and differ by more than an order of magnitude in coverage. Start with /api/v1/ct/dns/{domain} — the others are corroboration or a different question entirely.

RequestAnswershkr.secloudflare.com
GET /api/v1/ct/dns/{domain}Every hostname seen in CT-derived DNS data. The enumeration source.681053
GET /api/v1/ct/{domain}Hostnames that hold a certificate, with the attesting cert. Capped at 100 certs.628
GET /api/v1/search/smql?q=domain:*.{domain}Which subdomains have been scanned — not which exist.197
GET /api/v1/tls/{scan_id}SANs on the certificate actually served. The only source of wildcard names.10
GET /api/v1/ct/ip/{ip}Hostnames sharing one IP. Yields subdomains only when they share it.04
GET /api/v1/domains/{domain}/scansScans recorded for the domain and its subdomains.115
GET /api/v1/hosts/{domain}Every host we have seen for a domain, grouped by evidence: what the browser contacted, plus subdomains a third party asked us about that we confirmed resolve.4155

Measured 2026-08-22. Counts are distinct hostnames beneath the apex./ct/similar, /ct/timeline, /domain/stats and /search?q= return none and are not subdomain sources.

Recipe

# 1. Enumerate. Raise the cap for wide domains and always check the flag.
curl -s "https://scanmalware.com/api/v1/ct/dns/$D?subdomain_limit=5000" \
  | jq '{n: .subdomain_count, truncated: .subdomains_truncated, hosts: .subdomains}'

# 2. Dangling DNS: published in a certificate, no longer resolving.
#    These are subdomain-takeover candidates.
curl -s "https://scanmalware.com/api/v1/ct/dns/$D" \
  | jq -r '.dns_records[] | select(.resolution_error=="nxdomain") | .domain'

# 3. Wildcard names, which never resolve and so never appear above.
curl -s "https://scanmalware.com/api/v1/tls/$SCAN_ID" | jq -r '.sans.dns_names[]'

# 4. Which of them have actually been scanned.
curl -s -G "https://scanmalware.com/api/v1/search/smql" \
  --data-urlencode "q=domain:*.$D" --data-urlencode 'limit=100'

Three things that will bite you otherwise:

  • subdomains is capped at subdomain_limit (default 2000, max 5000). Always read subdomains_truncated — a partial list is otherwise indistinguishable from a complete short one.
  • A record's ip is often empty and that is meaningful: the hostname was in a certificate but did not resolve. resolution_error says why. Do not discard those — they are the interesting ones.
  • SMQL searches the scan corpus, not DNS. For hkr.se that is 1 host against 68 that exist. It answers "what have we looked at".

SMQL search filters

Every filter accepted by GET /api/v1/search/smql?q=<query> and by Advanced search: 127 filters and 20 has: checks. The live list, with the same fields, is GET /api/v1/search/smql/filters.

Syntax

text searchpaypal login
filterfield:value
quotedfield:"value with spaces"
comparisonfield:>value, field:<value, field:>=value, field:<=value
rangefield:value1..value2
wildcardfield:*.example.com
booleanfilter1 AND filter2, filter1 OR filter2
negation-field:value or NOT field:value
grouping(filter1 OR filter2) AND filter3
existencehas:feature
Core (14)
FilterDescriptionExample
url
text · wildcard
URL (substring match against the entry and final URL)url:paypal.com
domain
text · wildcard
Extracted domain namedomain:paypal.com
title
text · wildcard
Page title (substring match)title:login
nodriver_title
text · wildcard
Residential (VPN-egress) capture page title (substring match). Differs from `title` (the datacenter capture) when a site cloaks scanners — a scanner-cloaking phishing lure surfaces here even when the datacenter title is a decoy shell or a redirect target.nodriver_title:"Meta for Business"
scan_id
text
Exact scan ID (the /result/<id> identifier). Mainly useful to scope another query to a single scan, e.g. checking whether a specific scan matches a hunt anchor.scan_id:c7df0db2-ca1d-423c-866f-80d4cb3a43db
status
enum
Scan status
Values: completed, failed, error, queued, processing
status:completed
scan_type
enum
Scan visibility type
Values: public, unlisted, private
scan_type:public
worker
text
Worker ID that processed the scanworker:chrome-worker-1
load_time
float · compare · range
Page load time in secondsload_time:>5
submitted
date · compare · range
Scan submission timestampsubmitted:last7d
completed
date · compare · range
Scan completion timestampcompleted:>2024-01-01
error
text
Error message texterror:timeout
proxy
bool
Whether a proxy was usedproxy:true
http_status
int · compare · range
HTTP response status code in any transaction (200, 301, 403, 404, 500, etc.)http_status:403
Network (7)
FilterDescriptionExample
ip
inet
Server IP address (supports CIDR notation)ip:1.1.1.1
primary_ip
inet
Primary server IP address (supports CIDR notation)primary_ip:1.1.1.1
asn
int
Autonomous System Numberasn:13335
asn_org
text
ASN organization nameasn_org:Cloudflare
country
text
ISO 2-letter country codecountry:US
city
text
City namecity:"New York"
ip_count
int · compare · range
Number of unique IPs contactedip_count:>10
WHOIS (8)
FilterDescriptionExample
registrar
text · wildcard
Domain registrar nameregistrar:namecheap
domain_age
int · compare · range
Domain age in days (since registration)domain_age:<30
registration_date
date · compare · range
Domain registration dateregistration_date:>2024-01-01
expiration_date
date · compare · range
Domain expiration dateexpiration_date:<2024-12-31
whois_server
text
WHOIS server used for lookupwhois_server:whois.namecheap.com
nameserver
text · wildcard
Nameserver hostname (from RDAP data)nameserver:ns1.cloudflare.com
rir
enum
Regional Internet Registry
Values: RIPE, ARIN, APNIC, LACNIC, AFRINIC
rir:RIPE
ip_network
cidr
IP network CIDR block (from RDAP)ip_network:104.16.0.0/12
Security (12)
FilterDescriptionExample
verdict
enum
AI security classification
Values: LEGITIMATE, LOW_RISK, MODERATE_RISK, HIGH_RISK, CONFIRMED_SCAM, NOT_ASSESSED
verdict:HIGH_RISK
ai_risk_score
int · compare · range
AI risk score (0-100)ai_risk_score:>50
ai_confidence
int · compare · range
AI confidence percentage (0-100)ai_confidence:>80
device_code_phishing
bool
AI flagged device-code / OAuth-consent (EvilToken) phishingdevice_code_phishing:true
category
text
Content category (ML classification)category:"phishing scam"
safe_browsing
enum
Google Safe Browsing threat type
Values: MALWARE, SOCIAL_ENGINEERING, UNWANTED_SOFTWARE
safe_browsing:MALWARE
clamav
enum
ClamAV scan result
Values: clean, infected
clamav:infected
virus
text · wildcard
ClamAV virus/malware namevirus:Trojan
ioc
text
IOC indicator valueioc:evil.com
ioc_type
enum
IOC indicator type
Values: ip, domain, hash, url, email
ioc_type:domain
threat_feed
text
Threat intelligence feed sourcethreat_feed:OTX
rpki
enum
RPKI BGP origin validation status
Values: valid, invalid, not-found
rpki:invalid
TLS (23)
FilterDescriptionExample
cert_issuer
text · wildcard
Certificate issuer (CN or organization)cert_issuer:"Let's Encrypt"
cert_subject
text · wildcard
Certificate subject common namecert_subject:*.example.com
cert_org
text
Certificate subject organizationcert_org:"Google LLC"
cert_expired
bool
Certificate is expiredcert_expired:true
cert_self_signed
bool
Certificate is self-signedcert_self_signed:true
cert_wildcard
bool
Certificate is wildcardcert_wildcard:true
cert_ev
bool
Extended Validation certificatecert_ev:true
cert_lets_encrypt
bool
Let's Encrypt certificatecert_lets_encrypt:true
cert_valid
bool
Certificate chain is validcert_valid:false
cert_revoked
bool
Certificate is revokedcert_revoked:true
cert_weak_key
bool
Weak cryptographic key detectedcert_weak_key:true
tls_algorithm
text
TLS signature algorithmtls_algorithm:SHA256withRSA
key_algorithm
text
Public key algorithmkey_algorithm:RSA
key_size
int · compare · range
Public key size in bits (use with key_algorithm for meaningful results, e.g. key_algorithm:RSA key_size:<2048)key_size:<2048
cert_days
int · compare · range
Days until certificate expirycert_days:<30
cert_fingerprint
text
Certificate SHA-256 fingerprint (hex; case, colons and spaces ignored)cert_fingerprint:f63a5fa3717eadd1d7842690d859152eb53b081eb92f859b0a84d6bda43d2fb5
cert_sha1
text
Certificate SHA-1 fingerprint, as shown in Certificate Transparency logs (hex; case, colons and spaces ignored)cert_sha1:1992148f71c2c6ceea8e6b882182cb9fbbad7400
ja4x
text · wildcard
JA4X structural certificate fingerprint (issuer RDNs_subject RDNs_extensions). Describes how a certificate is BUILT, so it survives every string in it changing. The EXTENSION half (last segment) is the discriminating one - match it as a suffix, e.g. ja4x:*5318375af521. Avoid writing the separator in a wildcard pattern: SQL LIKE treats _ as a single-character wildcard, so *_5318375af521 is silently broader than it looks.ja4x:2bab15409345_2bab15409345_5318375af521
cert_risk
int · compare · range
Certificate risk score (0-100)cert_risk:>60
cert_shared
int · compare · range
Number of domains sharing this certificatecert_shared:>100
caa
bool
Has CAA DNS recordscaa:true
caa_compliant
bool
Certificate is CAA compliantcaa_compliant:false
ct_logged
bool
Certificate is in CT logsct_logged:false
JARM (2)
FilterDescriptionExample
jarm
text
JARM TLS fingerprint hashjarm:29d29d15d29d29d...
jarm_known
bool
Matches a known JARM signaturejarm_known:true
Technology (4)
FilterDescriptionExample
technology
text · wildcard
Detected technology nametechnology:WordPress
tech_category
text
Technology categorytech_category:cms
tech_version
text
Technology versiontech_version:1.12
cpe
text · wildcard
CPE identifiercpe:cpe:2.3:a:wordpress*
JavaScript (19)
FilterDescriptionExample
js_risk
enum
JS obfuscation risk level
Values: low, medium, high, critical
js_risk:high
js_risk_score
int · compare · range
JS max risk score (0-100)js_risk_score:>70
js_eval
int · compare
Number of eval() calls detectedjs_eval:>0
js_func_constructor
int · compare
Function() constructor callsjs_func_constructor:>0
js_hash
text
JS code segment SHA-256 hashjs_hash:a1b2c3d4e5f6...
js_tlsh
text
JS code segment TLSH fuzzy hashjs_tlsh:T1A1B2C3D4...
js_library
text · wildcard
Matched JavaScript library namejs_library:jquery
js_suspicious
bool
JS segment flagged as suspiciousjs_suspicious:true
js_obfuscated
bool
JavaScript is obfuscatedjs_obfuscated:true
obfuscation_score
int · compare · range
Obfuscation risk score (0-100)obfuscation_score:>50
js_cdn
text
CDN type serving the JavaScriptjs_cdn:cloudflare
js_server
text
HTTP server type for JavaScriptjs_server:nginx
js_npm
text
NPM package namejs_npm:react
fp_canonical
text
js-fp3 canonical AST hash — the obfuscation-resistant identity (identifier-renamed copies collapse to one hash)fp_canonical:4a624378be31194f607a8011f974f6bacc322d44077c507c1f431a3ae3b31b6b
fp_content
text
js-fp3 content SHA-256 — byte-identical script (or webpack module) occurrencefp_content:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
fp_tlsh
text
js-fp3 TLSH (locality-sensitive hash) — near-duplicate by fuzzy hashfp_tlsh:T1A21206E2…
similar_to
text
js-fp3 structurally similar script — scans containing one of the 1000 nearest occurrences (cosine ≥ 0.7 on the Layer-3 vector) to the script identified by the given canonical_ast_hash anchorsimilar_to:4a624378be31194f607a8011f974f6bacc322d44077c507c1f431a3ae3b31b6b
malware_family
text
Malware pattern categorymalware_family:miner
malware_pattern
text
Malware pattern namemalware_pattern:CoinHive
Hashes (9)
FilterDescriptionExample
phash
text
Perceptual screenshot hashphash:a1b2c3d4e5f6
dhash
text
Difference screenshot hashdhash:f0e1d2c3b4a5
ahash
text
Average screenshot hashahash:a1b2c3d4e5f6
whash
text
Wavelet screenshot hashwhash:a1b2c3d4e5f6
color_hash
text
Screenshot color hashcolor_hash:#a1b2c3
favicon_hash
text
Favicon MMH3 hashfavicon_hash:-12345678
tlsh
text
TLSH fuzzy hash of page content (exact match)tlsh:T1CA048E77329A063986558498E057430D9F20B543B50ACDBC7ABCBAD8BFDED06107BB78
ssdeep
text
ssdeep fuzzy hash of page content (exact match)ssdeep:3072:VfQho9PKBb9JsE9RHCbZgRjFtSBaw9QWg:yhoC9J395CbZgLtSL3gc
favicon_md5
text
Favicon MD5 hashfavicon_md5:d41d8cd98f00b204e9800998ecf8427e
Tracking (4)
FilterDescriptionExample
tracker
text
Tracker typetracker:google_analytics
tracking_id
text
Specific tracking IDtracking_id:UA-12345678
tracker_category
text
Tracker categorytracker_category:analytics
tracker_risk
text
Tracker risk leveltracker_risk:high
Content (16)
FilterDescriptionExample
ocr
text · wildcard
OCR text from screenshotocr:"verify your account"
ocr_language
text
OCR detected languageocr_language:en
pastejacking_severity
enum
Pastejacking severity level
Values: low, medium, high, critical
pastejacking_severity:high
bot_detection
text
Bot protection type encounteredbot_detection:cloudflare
bot_evasion
bool
Bot evasion was attemptedbot_evasion:true
is_clone
bool
Detected as a clone of a legitimate siteis_clone:true
clone_score
float · compare
Clone similarity scoreclone_score:>0.8
clearfake_type
text
ClearFake detection typeclearfake_type:eval_atob
ids_signature
text · wildcard
Suricata IDS signature nameids_signature:"ET TROJAN"
ids_category
text
IDS alert categoryids_category:"A Network Trojan was detected"
ids_severity
int · compare
IDS alert severity (1=highest, 4=lowest)ids_severity:1
ids_alerts
int · compare
Total IDS alert countids_alerts:>0
bundler
text
JavaScript bundler typebundler:webpack
bundle_modules
int · compare
Number of modules in bundlebundle_modules:>50
warning_page
bool
Browser warning page was detectedwarning_page:true
warning_type
text
Warning page typewarning_type:deceptive_site
Hosts (4)
FilterDescriptionExample
contacted_host
text · wildcard
Host the browser actually resolved and requested during the scan. Observed evidence. Supports *.example.com for subdomain queries.contacted_host:cdnjs.cloudflare.com
csp_host
text · wildcard
Host named in the page's Content-Security-Policy. DECLARED intent, not contact — the page may never have talked to it. Supports wildcards.csp_host:*.github.com
script_host
text · wildcard
Host of a script the browser actually loaded. Observed evidence. Supports wildcards.script_host:cdn.jsdelivr.net
js_host
text · wildcard
Host called from a URL sink inside script source (fetch/open/WebSocket/...). STATIC finding — roughly a third are corroborated by runtime, the rest being conditional or dead code. Supports wildcards.js_host:sentry.io
CT (5)
FilterDescriptionExample
ct_domain
text · wildcard
Domain in Certificate Transparency logsct_domain:*.paypal.com
ct_san
text
Certificate Subject Alternative Namect_san:*.example.com
ct_hash
text
Certificate hash in CT logsct_hash:abc123...
ct_log
text
CT log sourcect_log:Google
ct_issued
date · compare · range
Certificate issuance date in CTct_issued:>2024-01-01
Existence checks (20)
has:malwareMalware detected by ClamAV
has:trackerHas tracking codes
has:pastejackingPastejacking detected
has:iocHas IOC threat intelligence matches
has:jarmHas JARM TLS fingerprint
has:certificateHas TLS certificate data
has:screenshotHas screenshot
has:ocrHas OCR text extracted
has:bot_detectionBot protection was encountered
has:safe_browsingFlagged by Google Safe Browsing
has:clipboardHas clipboard events
has:cloneDetected as a clone site
has:clearfakeClearFake attack detected
has:idsHas IDS/Suricata alerts
has:rpki_invalidHas RPKI invalid result
has:pcapHas decrypted PCAP capture
has:fallbackHas fallback scan (bot bypass)
has:whoisHas WHOIS/RDAP domain data
has:webpackHas webpack/rollup bundle
has:phishingHas phishing detection result

API Endpoints

POST/api/v1/scan

Submit URL for Scanning

Submit a URL for scanning. Works anonymously for public and unlisted scans. Authenticate with a Bearer token (when logged in) or an API key with the scan:submit scope (X-API-Key header, created on your account page) to attribute the scan to your account; private scans require authentication and are visible only to you.

Parameters

NameTypeRequiredDescription
urlstringRequired
scan_typestringOptional
optionsstringOptional
csrf_tokenstringOptional

Response

{
  "scan_id": "string",
  "status": "string",
  "message": "string",
  "scan_type": "string",
  "submitted_at": "string"
}

Example

Request
curl -X POST "https://scanmalware.com/api/v1/scan" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "scan_type": "public"}'
Response
{
  "scan_id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "queued",
  "message": "Scan submitted successfully",
  "scan_type": "public",
  "submitted_at": "2025-08-20T16:30:00.000Z"
}