One reverse IP lookup on issued.live returned 532 hostnames, effectively all first observed inside the same four-day window. The endpoint answers what else lives at an address: every hostname the resolvers have recorded answering there, each with the date that pairing was first observed. One address goes in, and a list with structure in it comes back.
Addresses and hostnames below are placeholders. The calls are real, and they run against the Pro API reference.
The inverse lookup is one request
Passive DNS tooling answers what a domain resolves to. The inverse question turns a single observation into a set, which is what moves a thread forward.
curl -sS "https://issued.live/api/v1/ip/198.51.100.24?limit=500" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
The key travels in the header. There is no ?key= parameter, because query strings land in access logs, proxy logs and Referer headers. A key in the URL therefore leaves the request unauthenticated and answers 401.
Each row in hosts[] carries hostname, domain for the registrable domain, ip, first_seen, last_seen and observed. The envelope carries query, addresses, count, truncated, limit, order, and next_cursor when another page exists.
Read truncated first. A limit returns up to that many rows and promises nothing about completeness. A true there means the picture in front of you is partial.
Enumerating an address completely is a cursor walk
limit defaults to 500 and tops out at 50000. Out-of-range values are clamped rather than refused, so a request for a million quietly returns 50000. Busy hosting addresses hold far more names than that.
Past the cap, the cursor is the only correct route. Send ?after= with an empty value to begin, then pass back each response's next_cursor until one arrives without it.
curl -sS "https://issued.live/api/v1/ip/198.51.100.24?after=&limit=50000" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY" > page1.ndjson
The ordering changes when the cursor appears. Without after the page sorts by last_seen descending and cannot be resumed, since a re-observed name moves between pages. With after present the sort is the table's primary key, which never changes for a given observation.
Four parameter names people reach for answer 400: page, offset, skip and cursor. All four were once accepted and ignored, which returned page one with a 200 however many times you asked for page four. Code written against that behavior read the same page in a loop.
At a limit of 5000 or above the answer streams as newline-delimited JSON, one object per line. Records always carry hostname and the trailer carries end, so the two are unambiguous. A stream that dies mid-flight has no trailer and no cursor, and that absence is the error signal.
first_seen dates the association between a name and an address
first_seen is the earliest time the resolvers saw that hostname answer with that address. It records when the name arrived at its current host. When the name was created is a separate fact, and RDAP is where that one lives.
Take a domain registered years ago whose first_seen at its current address is three weeks old. That is an aged name that moved recently. It behaves like a new one while carrying the reputation of an old one.
The gap between the two dates is a reading, and it stays a reading. Treat a change of hands as an interpretation, and never assert who holds a name.
The same field takes a server-side window, on either bound alone:
curl -sS "https://issued.live/api/v1/ip/198.51.100.24?first_seen_from=2026-09-01&first_seen_to=2026-09-05&limit=5000" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
RFC3339, YYYY-MM-DD HH:MM:SS, YYYY-MM-DD and unix seconds all parse, and a missing zone means UTC. A malformed or reversed window answers 400.
Copy the published reasoning into your own API: "A limit is a preference, so we clamp it and answer the question you meant. A timestamp asserts which rows you want, and substituting a different window is how you end up with a gap you cannot see."
These observations begin in August 2026. A window earlier than that comes back empty because nobody was looking yet. Check the window before concluding an address sat unused.
The hostname list has a grammar
Co-location on shared hosting proves little by itself. The timing carried the weight in that case: names that arrive together were deployed together.
The shape of the names is the second measurement. Three greps classified most of that list in a few seconds.
jq -r 'select(.hostname) | .hostname' page1.ndjson | sort -u > names.txt
grep -cE '(clk|clks|trk|trks|track)' names.txt
grep -cE '[a-z]+[0-9]{2,}\.' names.txt
grep -cE '(scrty|sec-|-secure|verify)' names.txt
Of the 532, the click and redirect abbreviations came to 163, the leetspeak variants to 15 and the security-themed lures to 37. A fourth pass over insurance and quote wording caught 27 more. One query enumerated a disposable redirect fleet, and a grep fingerprinted how it names itself.
A grammar returns a candidate set rather than a finding. Cheap names bought in bulk look alike because one script generated them, and unrelated operators land on the same conventions.
What lifts a candidate above coincidence is a second independent link. Co-tenancy on one certificate, a shared public key, an account-specific nameserver pair or a registration inside the same hour each qualify.
Pattern search reaches the members on other hosts
An address holds the members parked there on the day you looked. The rest of the family sits elsewhere, and the grammar is what reaches them.
Pattern search matches a naming hypothesis against the corpus, next to the data. That is the only place it can run, because there is no wordlist and the space is combinatorial.
curl -sS -g \
"https://issued.live/api/v1/search?name=[a-z]{3,8}clk.com&ns=ns.example-dns.net&limit=500" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
The -g earns its place. Braces and brackets are curl's own globbing syntax, so without --globoff the pattern never reaches the API intact.
Patterns are written forwards, the way you say the name, with * for a run of characters, ? for exactly one, and a counted class such as [a-z]{3,8}. The count is required and bounded, with a ceiling of 64. An open class like [a-z]+ is refused, because an open bound is how a pattern silently becomes a full scan.
Every pattern must name a TLD, so *agent alone is refused and *agent.* means every TLD. Names are stored suffix-first, so pinning one turns the pattern into a key range. The reference measures anchored searches at 0.03 to 0.7 seconds, against 1 to 3.5 seconds for one that reads the whole key space.
The response reports anchored and key_prefix, so you can see which case you landed in.
Window mode reads the registration feed by date
Sending a time bound switches the search into window mode, which reads the registration feed by date. That is the right mode for "which names matching this grammar appeared last week". The reference measures that query at 0.094 seconds.
Cursors carry no meaning between the two modes, and the wrong one answers 400 instead of silently restarting the walk.
Every hit carries ns and cert_id, and the ns filter above is what keeps a grammar from collecting coincidences.
Batch lookup tests 500 candidates in one call
A search plus a key pivot produces a few hundred names. Looking them up one at a time is a few hundred requests against a concurrency gate. Batch lookup takes up to 500 in a single POST.
curl -sS "https://issued.live/api/v1/domains?include=timing" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY" \
-H "Content-Type: application/json" \
-d '{"domains":["name-one.example","name-two.example"]}'
Every input gets a row back in the order you sent it, duplicates included. The reply zips against your list without normalizing anything. Rows come back found, not_found, or rejected where the input never parsed as a registrable domain.
Those last two stay separate on purpose. A batch that dropped unparseable input would let you record a domain as absent when it was never queried.
Any include value drops the per-request cap to 100 names, each carrying up to 10 sub-entries. Sending more names than the cap truncates to it and sets truncated.
Pivot on the certificate, then on the key
A domain record publishes ssl_cert, the 32-hex cert_id, and that value is the bridge into the certificate endpoints.
curl -sS "https://issued.live/api/v1/cert/$CERT_ID" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
curl -sS "https://issued.live/api/v1/spki/$SPKI_SHA256?limit=500" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
The sans array lists the names a certificate covers, which is a link that survives a reverse proxy. spki_sha256 is a hash over the SubjectPublicKeyInfo, so two certificates carrying the same value were issued for one key pair. Often that is a renewal, and sometimes it is one operator across names that share nothing else.
| Link | Strength | Why |
|---|---|---|
| Shared address | Weak alone | A CDN address fronts unrelated tenants at scale, so co-location proves shared hosting. |
| Shared nameservers | Moderate | Strong when the pair is account-specific, weak when it is a large provider's default. |
| Shared certificate | Strong | Names packed onto one certificate were issued together, by one party, for one deployment. |
| Shared key | Strongest | One key pair across certificates means one holder of one private key. |
Read the coverage field on every key pivot before drawing a conclusion. Key hashes were first recorded on September 7, 2026, and certificates ingested earlier cannot be matched on one. A thin result from an older pivot therefore reads as unknown.
Certificate detail stays queryable for 14 days and then lives on in the archived daily files. A 404 for an older id reports that horizon and says nothing about whether the certificate existed.
ja4x fingerprints the issuance software a certificate authority runs. issued.live reports the value and offers no pivot on it. The value space is small enough that a match would return a large share of one CA's output.
Where the range sweep is the wrong instrument
Reverse IP has a sibling that takes a CIDR. Write the prefix slash as a hyphen, since a literal slash is a path separator and will not route.
curl -sS "https://issued.live/api/v1/range/198.51.100.0-24" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
A range covers at most 256 addresses, an IPv4 /24, and anything wider answers 400. On shared cloud space the surrounding /24 belongs to unrelated tenants. A sweep there returns hundreds of neighbors with nothing to do with your thread.
On dedicated hosting that trade-off inverts, and the /24 becomes the fastest way to see a whole rented block. Sweeping anything larger means iterating a /24 at a time.
Concurrency is the limit that bites
The per-minute ceiling rarely stops this work. Advanced queries are bounded by how many run at once on one key: one on Plus, two on Pro.
Reverse IP, range, pattern search, batch lookup and the provisioning feed each take a slot. Certificate, key, domain and timeline lookups take none.
Over the gate a request waits up to five seconds for a slot, then returns 503 timeout. It never queues, so a pile-up of slow queries cannot form. Branch on the retryable field and Retry-After rather than on the status number.
The timeout status stays 503 by design. This origin sits behind a CDN that replaces a 504 with its own error page, stripped of the JSON body.
Serialize a multi-block walk. The gate admits two at a time on Pro anyway, and concurrent cold range queries make each other slower.
The feeds keep the map current
A fleet enumerated on Tuesday is a snapshot. Two cursor-paged feeds turn a finished investigation into a standing one.
curl -sS "https://issued.live/api/v1/provisioning?max_hours_to_cert=6&ns=ns.example-dns.net" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
curl -sS "https://issued.live/api/v1/nrd?certified=1&max_hours_to_cert=1&limit=500" \
-H "Authorization: Bearer $ISSUED_LIVE_KEY"
The provisioning feed returns domains registered, certificated and pointed at a host inside one window. Any one of those facts is ordinary. All three inside an afternoon is a domain being stood up to be used.
The hours-to-certificate bound is what keeps that query affordable. On the reference's own measurements, widening it from one hour to six multiplies the candidates in a 72-hour window by roughly 19. Widening it again to 24 hours multiplies them by another 10.
Recent windows are thin by construction, and the response says so. Published coverage figures: 36.9% of candidates carry a DNS observation inside 24 hours, 83.9% inside 72 hours and 96.1% inside a week.
Rows without one are marked not_yet_observed, which records an observation nobody has made yet. It says nothing about whether the name resolves.
The newly registered domains feed runs in ascending time order from a cursor. A consumer resumes exactly where it stopped, so a scheduled job can miss a run without losing an event. Store next_cursor on every page, including the ones where caught_up comes back true.
Sub-hour certification runs at about 1.1% of certified registrations, against 8.4% taking over a week. The tight end of that filter is a small set. max_hours_to_cert requires certified=1, and sending it alone answers 400 instead of quietly doing nothing.
What the plans cover
issued.live opened paid plans on September 19, 2026, three of them. Pattern search, batch lookup and both feeds belong to Pro at $199 a month. Pro also carries 1,200 requests a minute, two advanced queries in flight, and daily files for DNS by vantage point, certificates and address history.
The earlier steps sit lower. Reverse IP, the CIDR sweep, the pivots and the domain timeline by API run on Plus at $99 a month, with one query in flight. Basic at $39 takes the daily domain and DNS files plus the extended record and the domain timeline on the website.
Unkeyed access stays free at 1,000 requests a day per address. Billing is monthly through PayPal, and sign-in is a code sent to your email. Full plan and limit detail sits on the pricing page.
Methodology
Every endpoint, parameter, cap and error code above was checked on September 18, 2026 against the issued.live Pro API reference, last updated September 15, 2026. Plan boundaries come from the pricing page on the same date, and the performance and coverage percentages are that site's published measurements. The 532-hostname classification comes from Tuxxin investigation work, and Daniel Jones reviewed the post before publication.
Top comments (0)