Programmatic access to the ctlogs.dev certificate index: search by domain, organization, serial or fingerprint, with history back to 2013 on the Pro plan.
Eleven GET methods under https://api.ctlogs.dev; /v1/spki, /v1/first-seen and /v1/hosts-history need the Pro plan.
| Method | Returns |
|---|---|
/v1/domain/{hostname} | certificates naming exactly this hostname, valid now or expired within 90 days (Pro: full archive) |
/v1/subdomains/{domain} | certificates for the domain and every name under it, valid now or expired within 90 days (Pro: full archive) |
/v1/hosts/{domain} | hostnames with a certificate valid now or expired within 90 days, one row each: certificate count, first/last seen, latest expiry |
/v1/org?q={name} | certificates by subject organization, valid now or expired within 90 days (Pro: full archive) |
/v1/serial/{serial} | certificates by serial number |
/v1/cert/{id} | full record of one certificate; /final.pem, /precert.der… for 7 days |
/v1/spki/{hash} | every certificate sharing one public key |
/v1/first-seen/{hostname} | earliest and latest CT record of a hostname, since 2013 |
/v1/hosts-history/{domain} | every hostname ever certified under a domain, since 2013 |
/v1/bimi?q={domain or name} | BIMI mark certificates (VMC/CMC) by domain or organization |
/v1/usage | the key’s plan and remaining quota |
Details: authentication and limits, plans, pagination, measured latency.
Base URL is https://api.ctlogs.dev. All endpoints are GET, all responses are JSON (UTF-8). Search results are sorted newest-first by not_before and paginated at up to 100 rows per page — see pagination. Path parameters must be URL-encoded. Cross-origin requests are allowed (Access-Control-Allow-Origin: *).
Anonymous requests run one request at a time per client; a request sent while the previous one is still in flight gets 429 with Retry-After: 1 and is not charged. The same callers are capped at 100 requests per hour (fixed UTC hours): 429 with Retry-After until the next hour, X-Hourly-Remaining on every response, nothing charged for a refusal. Requests without a key are served from a shared keyless pool of three concurrent queries inside the upstream pool of six — under load they wait up to 10 seconds for a slot, then get 503; an API key lifts you out of that pool. Keyless requests follow next_cursor through the first 10 pages of a query (1,000 rows); a deeper page answers 403, and any key, the free one included, pages as far as its quota goes. Pass a key as an Authorization: Bearer <key> header or a ?key=<key> query parameter. Keys come from the account cabinet: a free key for non-commercial use, paid plans for commercial use and more quota, the archive on Pro. Requests presenting an unknown or revoked key are rejected with 401 {"error": "invalid api key"}. Every keyed response carries X-RateLimit-Limit / X-RateLimit-Remaining for the month; /v1/usage returns the same balance without spending anything. A request ct-search rejects as malformed (400, e.g. a bad cursor) is refunded; a 404 is a real lookup and stays paid.
GET/v1/usage
The key's plan and balance, free of charge: not paced, not counted against the hourly cap, not deducted from the quota. Requires a key (401 otherwise). resets_at is the first of next month, UTC. Free keys also see the hourly window.
curl -H 'Authorization: Bearer YOUR_KEY' 'https://api.ctlogs.dev/v1/usage'
{
"plan": "standard",
"monthly_limit": 50000,
"used": 1234,
"remaining": 48766,
"resets_at": "2026-10-01T00:00:00Z"
}
A key may carry a monthly quota of API credits (calendar month, UTC). Organization search (/v1/org) and public-key search (/v1/spki) cost 10 credits per request; every other endpoint costs 1 credit — org search scans the full organization dictionary and SPKI search fans out to an unbounded set of certificates sharing one key (a single key can be reused by millions of certificates), each an order of magnitude more expensive to serve than the indexed lookups. Responses to quota-limited keys include X-RateLimit-Limit and X-RateLimit-Remaining headers (in credits); once the quota is spent, requests return 429 until the first of the next month.
curl -H 'Authorization: Bearer YOUR_KEY' 'https://api.ctlogs.dev/v1/domain/example.com'
Every plan covers all currently valid certificates plus those expired within the last 90 days — the full current attack surface of a domain. The Pro plan adds the deep archive: certificates back to 2013, first-seen dates per hostname, historical subdomain discovery and public-key search.
| Plan | Credits / month | Limits | History | Pro methods |
|---|---|---|---|---|
| Anonymous | — | 100 per hour, one at a time, shared keyless pool | until expiry + 90 days | — |
| Free key | 10,000 | 100 per hour, one at a time | until expiry + 90 days | — |
| Standard | 50,000 × packages | none | until expiry + 90 days | — |
| Pro | 100,000 × packages | none | full archive since 2013 | /v1/spki, /v1/first-seen, /v1/hosts-history |
Windowed list responses (/v1/domain, /v1/subdomains, /v1/org) carry history_window_days: 90; the first page adds history_truncated (true when older certificates exist) and upgrade. /v1/hosts lists names with at least one certificate inside the window and carries history_window_days only. Pro methods answer 403 {"error": "requires the Pro plan — https://account.ctlogs.dev/"} to other callers, without charging credits.
Licence. Every paid plan covers your own operations, reports for your clients included; Pro also lets you show results to your customers in your own product or service, under your own brand. Reselling or redistributing the results (feeds, bulk exports, APIs, datasets) is not included in any plan — ask contact@ctlogs.dev for a data licence. Details in the terms.
Server-side latency measured on 2026-09-03 over 1 212 real queries from the access log (cold result cache, one request in flight, production load): domain 26 / 31 ms, subdomains 46 / 54 ms, hosts 41 / 49 ms, serial 43 / 51 ms, cert 109 / 182 ms, org 352 / 516 ms (p50 / p90). End-to-end from Europe through Cloudflare adds roughly 40–60 ms. Method and raw numbers: the measurement is repeated after major changes.
GET/v1/domain/{hostname}
Certificates whose subject CN or SAN dNSName equals {hostname} exactly, as logged. A wildcard certificate for *.example.com is a distinct name and is not returned for sub.example.com — use the subdomains search to see both. History: certificates valid now or expired within the last 90 days; the full archive on Pro.
curl 'https://api.ctlogs.dev/v1/domain/example.com'
GET/v1/subdomains/{domain}
Certificates for {domain} itself and every name under it — www.example.com, *.example.com, a.b.example.com, … Equivalent to the *.example.com query on the website. History: certificates valid now or expired within the last 90 days; the full archive on Pro.
curl 'https://api.ctlogs.dev/v1/subdomains/example.com'
GET/v1/hosts/{domain}
Every distinct hostname under {domain} with a certificate that is valid now or expired within the last 90 days (the apex itself included, wildcards such as *.example.com inline), one row per hostname instead of one per certificate: certs (how many of those certificates named it), first_seen / last_seen (first and latest of them) and last_not_after (expiry of the latest one); responses carry history_window_days: 90. Hostnames whose last certificate expired earlier — the history since 2013 — are in /v1/hosts-history (Pro). Rows come in reversed-name order (example.com, *.example.com, a.example.com, www.example.com, …), 100 per page with the usual has_next / next_cursor; the website shows the first page only, paging needs an API key.
curl 'https://api.ctlogs.dev/v1/hosts/example.com'
{
"hosts": [
{"host": "example.com", "certs": 5, "first_seen": "2025-09-02T09:14:02Z",
"last_seen": "2026-08-30T11:02:57Z", "last_not_after": "2026-11-28T23:59:59Z"},
{"host": "*.example.com", "certs": 2, "first_seen": "2026-02-20T08:30:15Z",
"last_seen": "2026-05-22T08:30:15Z", "last_not_after": "2026-08-20T08:30:14Z"}
],
"has_next": false,
"next_cursor": "",
"duration_ms": 47,
"history_window_days": 90
}
GET/v1/org?q={name}
Certificates by subject organization (O=). Queries of 4+ characters match case-insensitively anywhere in the name (paypal finds “PayPal, Inc.”); shorter queries must match the full name exactly (so EY still resolves). Rows from this method carry subject_cn and a domains sample instead of issuer/key columns. Costs 10 API credits per request (see limits). History: certificates valid now or expired within the last 90 days; the full archive on Pro.
curl 'https://api.ctlogs.dev/v1/org?q=paypal'
GET/v1/serial/{serial}
Finds certificates by serial number: 4–42 hex characters, separators (:, -, spaces) and leading zero bytes tolerated. Serials are not globally unique, so one serial can return certificates from several CAs.
curl 'https://api.ctlogs.dev/v1/serial/0624d0ab311558780b7d5213b9631831'
GET/v1/spki/{hash}
Pro plan — finds every certificate sharing one public key: {hash} is the SHA-256 of the SubjectPublicKeyInfo (64 hex characters, separators tolerated) — the value OpenSSL prints as openssl x509 -pubkey | openssl pkey -pubin -outform DER | sha256sum. Useful for tracking key reuse across certificates and CAs. A key shared by more than 1,000 certificates (shared-hosting and CDN keys) lists its first 1,000 in issuer/serial order and every page carries "truncated": true; other keys list in full.
curl -H 'Authorization: Bearer YOUR_KEY' \ 'https://api.ctlogs.dev/v1/spki/0856752f53199a673dcc955c137fe1f5b105a180528acb320bb3eddf15103a9b'
GET/v1/first-seen/{hostname}
Pro plan. The earliest and latest Certificate Transparency record of one hostname: the SCT timestamp, issuer and serial of the first record, the earliest validity start (min_not_before, also mirrored as first_logged.not_before), the latest record and the latest expiry (each record is identified by issuer + serial — the certificate itself is at /v1/serial/{serial}). A hostname that never had a certificate of its own but lives under a wildcard gets the wildcard's history: matched names the record actually returned — the hostname itself, or its one-label wildcard parent such as *.example.com (a wildcard is also queryable as a name of its own). last_logged and max_not_after are null when the archive holds only the first record of the name (names seeded from our own 2025–2026 history carry no later record until the name is certified again). Backed by the archive index (2013 onwards). 1 credit; 404 when neither the name nor its wildcard parent ever appeared in CT. When only the wildcard one label below exists (*.{hostname}, which covers names under the hostname, not the hostname itself), the 404 names it: {"error": "no CT record for this name; only *.{hostname} exists"} — query that wildcard for its history.
curl -H 'Authorization: Bearer YOUR_KEY' 'https://api.ctlogs.dev/v1/first-seen/www.example.com'
{
"name": "www.example.com",
"matched": "www.example.com",
"first_logged": {"sct_ts": "2015-03-12T09:14:02.331Z", "not_before": "2015-03-12T00:00:00Z",
"issuer": "CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US",
"serial": "0E64C5FBC236ADE14B172AEB41C78CB0"},
"min_not_before": "2015-03-12T00:00:00Z",
"last_logged": {"sct_ts": "2026-08-30T11:02:57.104Z", "issuer": "…", "serial": "…"},
"max_not_after": "2026-11-28T23:59:59Z",
"duration_ms": 4
}
GET/v1/hosts-history/{domain}
Pro plan. Every hostname ever seen in a certificate under {domain} since 2013 (the apex and wildcards included), with the first SCT timestamp, the earliest validity start and the latest expiry; last_not_after is null when the latest record is unknown (see first-seen). Sorted by name, 100 per page, ?after=<next_cursor> for the next page; 1 credit per page. For the current surface with certificate counts use /v1/hosts.
curl -H 'Authorization: Bearer YOUR_KEY' 'https://api.ctlogs.dev/v1/hosts-history/example.com'
{
"apex": "example.com",
"hosts": [
{"name": "example.com", "first_seen": "2014-01-07T18:20:11.512Z", "first_not_before": "2014-01-07T00:00:00Z",
"last_not_after": "2026-11-28T23:59:59Z"},
{"name": "old-staging.example.com", "first_seen": "2016-05-02T07:44:09.001Z", "first_not_before": "2016-05-02T00:00:00Z",
"last_not_after": "2017-05-02T23:59:59Z"}
],
"has_next": true,
"next_cursor": "moc.elpmaxe.gnigats-dlo",
"duration_ms": 61
}
GET/v1/bimi?q={domain or organization}
Verified and Common Mark Certificates (VMC/CMC) — the certificates behind brand logos in BIMI e-mail — as on ctlogs.dev/bimi. A query with a dot is a domain: marks whose SAN list holds it or a name under it (*. and a trailing dot are dropped). Anything else matches case-insensitively anywhere in the subject organization, the subject CN or the word mark. Add type=domain or type=org to override the guess — for an organization name with a dot, say Booking.com B.V.. Newest first, 50 rows per page with has_next / next_cursor. Every plan, the anonymous one included; 1 credit per request.
Each row carries the subject, issuer and trademark fields, the certificate’s domains, kind (VMC or CMC) and the CT log entry it came from. The logo itself is not inlined: logo_url points to a sanitised copy of the certificate’s SVG on ctlogs.dev and is absent when the certificate carries no logo; logo_hash_ok says whether the SVG matches the hash in the certificate. page_url, pem_url and der_url lead to the mark’s page and its body.
curl 'https://api.ctlogs.dev/v1/bimi?q=cnn.com'
{
"query": "cnn.com",
"type": "domain",
"rows": [
{
"id": "f468559206fd370c",
"kind": "VMC",
"subject_o": "Cable News Network, Inc.",
"subject_cn": "Cable News Network, Inc.",
"subject_c": "US",
"subject_dn": "SERIALNUMBER=2976730,CN=Cable News Network\\, Inc.,O=Cable News Network\\, Inc.,STREET=190 Marietta St NW,L=Atlanta,ST=Georgia,C=US",
"issuer_dn": "CN=DigiCert Verified Mark RSA4096 SHA256 2021 CA1,O=DigiCert\\, Inc.,C=US",
"domains": ["cnn.com"],
"not_before": "2026-08-28T00:00:00Z",
"not_after": "2027-09-01T23:59:59Z",
"serial_hex": "0cb658999c795a3a19c7ee4434a810bd",
"sha256": "c32882230aa19b1b6e50230928f4c2751602b1dad06955121f9bd4f56393b9d7",
"is_precert": false,
"word_mark": "",
"mark_type": "Registered Mark",
"trademark_office": "",
"trademark_country": "US",
"trademark_registration": "5817930",
"logo_url": "https://ctlogs.dev/bimi/f468559206fd370c/logo.svg",
"logo_hash_ok": true,
"page_url": "https://ctlogs.dev/bimi/f468559206fd370c",
"pem_url": "https://ctlogs.dev/bimi/f468559206fd370c.pem",
"der_url": "https://ctlogs.dev/bimi/f468559206fd370c.der",
"log_id": "VVlTrjCWAIBs0utSCKbJnpMYKKwQVrRCHFU2FUxfdaw=",
"log_url": "https://gorgon.ct.digicert.com/log/",
"entry_idx": 41616,
"sct_ts": "2026-09-12T01:51:55.898Z"
}
],
"has_next": false,
"next_cursor": "",
"duration_ms": 12
}
GET/v1/cert/{id}
The full record for one certificate: subject and issuer DNs, complete SAN list, validity, key and signature info, policy OIDs, precert/final fingerprints, and every CT log sighting with entry index and SCT timestamp. {id} is the id value returned by the search methods above, or a 64-hex SHA-256 fingerprint (of the precertificate or the final certificate, separators tolerated).
precert_sha256 is the SHA-256 of the precertificate DER exactly as logged (the value crt.sh shows for the precertificate), final_sha256 that of the final certificate; either can be empty when that leaf form was not logged or its hash was not retained.
curl 'https://api.ctlogs.dev/v1/cert/000000b50624d0ab311558780b7d5213b9631831'
The raw body is kept for 7 days after the certificate is first seen in CT. While it is archived, download it by appending /final.pem, /final.der, /precert.pem or /precert.der; afterwards these answer 404 {"error": "certificate body not archived"} and the originating log (see sightings) is the source. The precertificate body is there for nearly every certificate; the final body only when a log received the final certificate, which is about half of them. precert_body_archived and final_body_archived in the record say which downloads are available, and precert_body_bytes / final_body_bytes give their sizes.
Search responses return up to 100 rows plus has_next and next_cursor. To fetch the next page, repeat the same request with ?after=<next_cursor> (cursor= is accepted as an alias). The cursor is an opaque token — do not parse it. Without a key a query pages 10 pages deep; with one — or signed in on ctlogs.dev, which draws on the same monthly allowance — as far as the quota goes.
curl 'https://api.ctlogs.dev/v1/subdomains/example.com?after=NEXT_CURSOR'
{
"rows": [
{
"id": "000000b50624d0ab311558780b7d5213b9631831",
"match": "example.com",
"not_before": "2026-07-29T22:10:08Z",
"not_after": "2026-10-27T22:17:21Z",
"serial_hex": "0624d0ab311558780b7d5213b9631831",
"issuer": "DigiCert Global G3 TLS ECC SHA384 2020 CA1",
"key_algo": "ECDSA P-256",
"san_count": 9
}
],
"has_next": true,
"next_cursor": "MTc1MzgyMDIwOTAwMDAwMDAwMHwxODV8…",
"duration_ms": 132
}
| Field | Meaning |
|---|---|
| id | Stable certificate id; feed it to /v1/cert/{id} or https://ctlogs.dev/cert/{id}. |
| match | The name that matched: a SAN dNSName for domain methods, the subject organization for /v1/org, the subject CN for /v1/serial and /v1/spki. |
| not_before, not_after | Validity window, RFC 3339 UTC. |
| serial_hex | Serial number, minimal big-endian hex. |
| issuer, key_algo, san_count | Issuer CN, public-key algorithm (“RSA 2048”, “ECDSA P-256”), SAN count. Domain, serial and SPKI methods only. |
| subject_cn, domains, domains_more | Subject CN, a sample of the certificate’s domains and how many more it has. /v1/org only. |
{
"id": "000000b50624d0ab311558780b7d5213b9631831",
"issuer_dn": "C=US, O=DigiCert Inc, CN=DigiCert Global G3 …",
"subject_dn": "C=US, ST=California, O=Internet Corporation …",
"subject_cn": "www.example.org",
"serial_hex": "0624d0ab311558780b7d5213b9631831",
"san_dns": ["example.com", "www.example.com", "…"],
"not_before": "2026-07-29T22:10:08Z",
"not_after": "2026-10-27T22:17:21Z",
"sig_algo": "ECDSA-SHA384",
"pubkey_sha256": "b2b0fe1b…",
"is_ca": false,
"ext_key_usage": ["server_auth", "client_auth"],
"policy_oids": ["2.23.140.1.2.2"],
"precert_sha256": "56b93a54…",
"final_sha256": "91a44b23…",
"precert_first_seen": "2026-07-29T22:17:21Z",
"final_first_seen": "2026-07-29T22:19:03Z",
"duration_ms": 41,
"sightings": [
{
"log_id": "0DE1F2302BD30DC140621209EA552EFC47747CB1D7E930EF0E421EB47E4EAA34",
"log_url": "https://ct.googleapis.com/logs/us1/argon2026h2/",
"operator": "Google",
"entry_idx": 480932871,
"is_precert": true,
"sct_ts": "2026-07-29T22:17:21Z"
}
]
}
precert_first_seen / final_first_seen are the earliest SCT timestamps among the certificate’s sightings, per leaf form; a form that was never logged is null.
Errors are JSON with the HTTP status code set:
{"error": "one request at a time — wait for your previous request to finish, or use a paid key from https://account.ctlogs.dev/"}
| Status | Meaning |
|---|---|
| 400 | Malformed query — bad hostname, non-hex serial or hash, invalid cursor, a /v1/bimi query without q. |
| 401 | The presented API key is unknown or revoked. |
| 403 | Paging /v1/hosts needs an API key, or a Pro-only method (/v1/spki, /v1/first-seen, /v1/hosts-history) was called by a non-Pro caller. |
| 404 | No certificate with that id or fingerprint (or, for /v1/first-seen, a hostname never seen in CT, not even under its wildcard parent; the error names *.{hostname} when only that wildcard exists). |
| 429 | Limit hit: anonymous or free key with a request already in flight (one at a time — retry when it finishes) or past its 100 requests for the hour, or a keyed monthly quota exhausted. |
| 503 | Server busy — retry with backoff. |