API & query reference

The tttx API is free — unlike Shodan. Sign up for a key (1,000 requests/day). The same query language powers the site search box and the API.

Authentication

Send your key in the X-API-Key header (recommended) or as ?key=. Only the /api/v1/* endpoints require a key.

Endpoints

EndpointPurpose
GET /api/v1/host?ip=All services on one IPv4 host.
GET /api/v1/search?q=&page=Hosts matching a query (20/page, collapsed by host).
GET /api/hitlist?q= ProRisk-ranked hosts (KEV + public exploit + CVSS + exposure) with a reason per host. Analyst tool — Pro key or admin session.
GET /api/graph?ip= ProCert/SAN/favicon/JARM pivot graph — a seed host's shared-infrastructure siblings as nodes+edges. Pro key or admin session.
GET /api/fingerprints?by= ProCorpus-wide fleets clustered by jarm/server/favicon/issuer/product, with per-cluster CVE counts. Pro key or admin session.
GET /api/changes?type=&since= ProPosture-change feed from re-scan diffs: new CVEs (KEV-flagged), exposures, defacements, cert swaps, version changes. Pro key or admin session.
GET /api/outliers?q= ProAnomaly detectors: data stores on odd ports, cleartext credential pages, untrusted TLS on high-trust sites, shells on web ports. Pro key or admin session.
GET /api/opendirs?q= ProPublic "Index of /" listings ranked by sensitive filenames. Pair with opendir_triage. Pro key or admin session.
GET /api/opendir_triage?ip=&port= ProLive-fetch a listing + AI read for exposed secrets/backups/source. Pro key or admin session.
GET /api/fleet_narrative?by=&key= ProAI intel brief for an infrastructure cluster (scale, stack, geography, CVE/KEV posture). Pro key or admin session.
GET /api/visual_id?ip=&port= ProVision model names the product/vendor from a screenshot (stored as product_guess). List mode without ip=. Pro key or admin session.
POST /api/analyst ProAgentic analyst: plans + runs tttx queries to answer a natural-language question (async; poll GET ?job=). Pro key or admin session.
GET /api/similar?ip=Hosts whose rendered page looks like the seed host's (visual kNN). See Vector search.
GET /api/semantic?q=Hosts whose page means the same as a free-text phrase (semantic kNN). See Vector search.
GET /api/statsCorpus totals + top ports/products (no key).
GET /api/ownership?q=&asn=IPv4 ownership by ASN + subnets (no key).
GET /api/v1/ai/host?ip= ProAI risk assessment + mitigation for a host.
POST /api/v1/ai/query ProNatural language → a tttx query string (JSON {"text":…}).
POST /api/v1/ai/ask ProAnalyst assistant (JSON {"prompt":…, "model":"quick|reason"}).

Endpoints tagged Pro require a Pro key — "AI testing & mitigation". They call our local models, so a response can take a few seconds to a minute.

URL-encode spaces in q as + or %20 (e.g. q=product:nginx+port:443).

Query filters

A query is space-separated tokens. key:value tokens filter; bare words are full-text (matched against banners, page titles, product and AS names). An IP/CIDR bare token filters by address.

FilterExamplesMatches
(bare text)nginx, loginFull-text across banners, titles, product & AS name.
ip:ip:1.1.1.1, ip:1.0.0.0/24, ip:102.0Exact IP, CIDR, or dotted prefix.
port:port:22, port:80,443, port:8000-8100Host has the port open. Comma = any (OR); a-b = range.
ports_all:ports_all:22,443Host has all listed ports open (AND).
product:product:nginx, product:OpenSSHIdentified service product (exact).
country:country:USISO-2 country (RIR-authoritative).
asn:asn:7018, asn:AS7018Autonomous system number.
org:org:ComcastAS organization name (text match).
owner:owner:CogentRIR registrant (substring, case-insensitive).
hostname:hostname:example.comTLS cert CN/SAN & page text (fuzzy match).
san:san:vpn.example.comExact TLS cert Subject Alternative Name. Facetable — the search response's facets include a san list of the most common SANs seen.
server:server:"nginx/1.24.0 (Ubuntu)"Exact HTTP Server header (quote values with spaces).
issuer:issuer:Sectigo, issuer:"C=US, O=Let's Encrypt, CN=R3"TLS cert issuer — case-insensitive substring, or exact for a full DN.
cert:cert:34ed5c7b…Exact certificate by SHA-256 fingerprint (all hosts serving the identical cert).
jarm:jarm:2ad2ad0002ad2ad…Active JARM TLS-stack fingerprint (clusters same-software/appliance servers).
favicon:favicon:999357577Shodan-style MMH3 favicon hash (same web app/brand across hosts).
status:status:200, status:401HTTP response status code.
has_ssl:has_ssl:trueTLS enabled on the service.
expired:expired:trueExpired TLS certificate.
self_signed:self_signed:trueSelf-signed certificate.
cve:cve:CVE-2021-41773A specific CVE is present.
has_vuln:has_vuln:trueHas a likely-real CVE (false = none). Excludes backport-suspect findings — version-matches on a distro-managed package (OpenSSH, Apache, …) on a backporting distro (Ubuntu/Debian/RHEL/…), which the distro has very likely patched. Still findable via exact cve:.
cvss:cvss:>=9, cvss:>7.5, cvss:9, cvss:7-9Max CVSS of any likely-real CVE (backport-suspect excluded, as with has_vuln:). Operators > >= < <=, or a band a-b.
os:os:ubuntu, os:debian, os:centosOS/distro inferred from the SSH banner package suffix or HTTP Server header.
backport:backport:confirmed-vulnerable, backport:confirmed-patched, backport:heuristicFilter by backport confidence (OpenSSH is tracker-confirmed against Ubuntu/Debian fixed versions; others are heuristic).
latency:latency:<20, latency:>=200, latency:50TCP-handshake RTT in ms. Operators > >= < <= (bare number = at most).
tag:tag:control-panel, tag:login, tag:wordpressDerived/heuristic tag — protocol, stack, exposure, or page-type category (see the tag list below).
label:label:"login page", label:"admin dashboard / control panel"Page type from the screenshot/OCR classifier (quote multi-word values). See the label list below.
app: / plugin:app:WordPress, plugin:woocommerce, app:wp-plugin:elementorStacked app / CMS / WordPress plugin (plugin: is shorthand for app:wp-plugin:).
app:…@versionapp:WordPress@6.8.8 (exact), app:WordPress@6.8.* (prefix), app:WordPress@<6 / @>=5 / @<=6.8 (compare), app:WordPress@5-6 (band), plugin:woocommerce@8.5Pin a stacked app to a version. Comparisons (< <= > >=) and bands (a-b, half-open) sort numerically. Precise: product + version are bound to the same app (nested), so a plugin's version can't leak into a core-version filter.
exposure:exposure:open-redis, exposure:weak-rsa-keyA specific no-auth / weak-crypto exposure.
no_auth:no_auth:trueAny no-auth / anonymous exposure (Redis, Mongo…).

Tags & page-type labels

Every service carries a tags array (fast, keyword-exact — use with tag:) and, if a screenshot was captured, a page-type label from the vision/OCR classifier (use with label:"…", quoting multi-word values). Hunt for interesting surfaces like this:

KindValuesExample
Protocol / transportweb, tls, ssh, ftp, smtp, imap, pop3, dnstag:web tag:tls
Certificateself-signed, expired-certtag:self-signed
Riskvuln, no-auth, weak-key, tarpittag:no-auth
Stackwordpress, wordpress-plugin, wordpress-theme, + per-product tagstag:wordpress
Page type (from OCR/vision)login, control-panel, webapp, ecommerce, blog-news, webmail, vpn, dir-listing, api-endpoint, iot-camera, defacedtag:vpn
label: values"login page", "admin dashboard / control panel", "web application / SaaS", "online store / e-commerce", "blog / news / media", "corporate / business site", "webmail", "VPN / remote-access portal", "directory listing", "API / JSON endpoint", "camera / IoT device UI", "default/placeholder page", "error page", "other / uncategorized"label:"web application / SaaS"

The short page-type tag:s are set from the OCR text during an OCR pass, so they cover image/JS-rendered pages the DOM classifier misses. tag:login and label:"login page" overlap; the tag is quicker to type, the label is exact.

Combining filters & gotchas

Tokens combine with AND at the service level. Because each open port is its own record, filters that describe a single service combine naturally:

But two port: filters describe two different services, so port:22 port:443 matches nothing (no single record is both). To require a host to have several ports open, use ports_all::

Vector search (visual & semantic)

The keyword filters above match exact values. Vector search matches by similarity instead — "show me pages that look like this" and "find pages that mean this", even when they share no keywords. It's backed by two embeddings we compute per host from its screenshot:

VectorWhat it encodesModel / dims
screenshot_vecThe visual appearance of the rendered page (layout, colours, logos).CLIP ViT-B-32 · 512-d
text_vecThe meaning of the page's title + on-page (OCR) text + service banner.nomic-embed-text · 768-d

Both are indexed as OpenSearch knn_vector fields (HNSW, cosine). Nearest-neighbour lookups are ranked by cosine similarity, returned per result as similarity (1.0 = identical).

Visual similarity — /api/similar

Give it a seed ip; it returns the hosts whose screenshots are closest to that host's. No text needed — this finds the same login portal, appliance UI, or phishing-kit template deployed across many IPs, including ones with no shared banner or certificate. In the web UI, open any host and click “Similar pages”.

ParamDefaultMeaning
ip (required)Seed IPv4. Its stored screenshot_vec is the query vector (no GPU call).
portanyPick a specific service's screenshot when the host has several.
fieldscreenshot_vecscreenshot_vec (visual) or text_vec (by meaning of the seed's text).
qOptional structured filter to narrow the neighbour pool (same grammar as search).
size24Max hosts to return (1–100).

Semantic search — /api/semantic

Give it a natural-language q; we embed your phrase with the same model that produced text_vec, then return the hosts whose page text is closest in meaning. So database admin control panel surfaces phpMyAdmin, Adminer and Odoo logins even when the page never uses those words. In the web UI, prefix the search box with ~:

ParamDefaultMeaning
q (required)Free-text phrase describing the page you're after.
andOptional structured filter applied on top (same grammar as search), e.g. and=country:DE.
size24Max hosts to return (1–100).

Coverage. A host is only returned once its screenshot has been vectorised (an ongoing backfill over ~42k thumbnails). Hosts without a screenshot — or not yet processed — won't appear. Visual results need screenshot_vec; semantic results need text_vec, which exists only when the page had a title/OCR text/banner to embed.

Similarity vs. filters. kNN returns a fixed top-k ranked by closeness, not a filtered set — so there are no facets or deep pagination, and a low-scoring tail is expected. Combine with structured filters (q/and) to keep the neighbour pool tight.

Worked examples

Limits & errors

Machine-readable spec

An OpenAPI 3.0 document describes every endpoint, parameter, and response schema. It's served with CORS, so you can point Swagger UI, Redoc, Postman, or a client generator straight at it. The query filters are also enumerated under the q parameter's x-tttx-filters extension.

View openapi.json

Questions or abuse reports: abuse@tttx.net.