API Documentation

certs.lol is API-first. Same URL, content-negotiated.

Quick Start

$ curl -s https://certs.lol/stripe.com | jq

Endpoints

GET /{domain}

Scan a domain's TLS configuration. Returns full scan result with grade, protocols, certificate details, cipher suites, and more.

$ curl -s https://certs.lol/stripe.com | jq '.grade'
"A+"

GET /{domain}?force

Bypass cache and force a fresh scan. Still counts against rate limit.

$ curl -s "https://certs.lol/stripe.com?force" | jq '.grade'
"A+"

GET /{ip}

Scan a specific IP address. DNS-dependent fields (CAA, DANE, DNSSEC, multi-IP) are omitted.

$ curl -s https://certs.lol/1.1.1.1 | jq '.certificate.subject'
"cloudflare-dns.com"

GET /

Service info and usage hint.

Content Negotiation

The same URL serves JSON for API clients and HTML for browsers:

Rate Limiting

Why 60/hr? TLS scans are resource-intensive — each request triggers a real probe that makes live TLS connections to the target from a Fly.io edge node. This is significantly heavier than DNS lookups, which is why certs.lol's limit is lower than other .lol tools (e.g. ns.lol allows 120/hr).

For unlimited local scanning, install the CLI — same engine, no rate limits, no middleman.

Rate limits exist to prevent abuse and keep hosting costs near zero. If you need more volume, grab the source and run your own instance, or use the full domain report at yoke.lol.

Response Shape

{
  "grade": "A+",
  "issuer": "CN=WE1,O=Google Trust Services,C=US",
  "subject": "CN=example.com",
  "valid_from": "2026-01-01T00:00:00Z",
  "valid_to": "2026-06-30T23:59:59Z",
  "key_alg": "ECDSA",
  "key_size": 256,
  "protocols": ["TLS 1.3", "TLS 1.2"],
  "chain_depth": 3,
  "chain_valid": true,
  "chain_certs": [
    {
      "subject": "CN=example.com",
      "issuer": "CN=WE1,O=Google Trust Services,C=US",
      "valid_from": "2026-01-01T00:00:00Z",
      "valid_to": "2026-06-30T23:59:59Z",
      "key_alg": "ECDSA", "key_size": 256,
      "serial": "74AA66CF...",
      "is_self_signed": false,
      "signature_alg": "ECDSAWithSHA256"
    },
    { "subject": "CN=WE1,...", "issuer": "CN=GTS Root R4,...", "...": "..." }
  ],
  "sans": ["example.com", "*.example.com"],
  "serial": "74AA66CF6F7314CE0EBD4122DFC80C79",
  "fingerprint": "A5F1682E76B7F050D62B...",
  "probe_ms": 218,
  "error": null,
  "ciphers": [
    { "name": "TLS_AES_128_GCM_SHA256", "id": 4865, "strength": "strong" },
    "..."
  ],
  "ocsp_stapling": true,
  "sct_count": 2,
  "has_scts": true,
  "forward_secrecy": true,
  "key_exchange": "ECDHE (TLS 1.3)",
  "target": "example.com",
  "is_ip": false,
  "scanned_at": "2026-06-13T03:33:08.052Z",
  "days_remaining": 72,
  "cipher_summary": { "strong": 5, "acceptable": 2, "weak": 0, "insecure": 0 },
  "hsts": {
    "enabled": true, "max_age": 31536000,
    "include_subdomains": true, "preload": true,
    "on_preload_list": true
  },
  "http3": {
    "supported": true, "http2": true,
    "alt_svc": "h3=":443"; ma=86400"
  },
  "dns_security": {
    "dnssec": true,
    "caa": ["issue digicert.com", "issue letsencrypt.org"],
    "dane_tlsa": null
  },
  "compliance": [
    {
      "framework": "pci-dss-4",
      "display_name": "PCI DSS 4.0",
      "meets_requirements": true,
      "findings": [...]
    },
    {
      "framework": "nist-800-52r2",
      "display_name": "NIST 800-52r2",
      "meets_requirements": true,
      "findings": [...]
    },
    {
      "framework": "hipaa",
      "display_name": "HIPAA",
      "meets_requirements": true,
      "findings": [...]
    }
  ],
  "_meta": {
    "version": "1.0.0",
    "cache_hit": false,
    "cache_ttl": 21600,
    "docs": "https://certs.lol/api/docs",
    "dns_report": "https://ns.lol/example.com",
    "full_report": "https://yoke.lol/example.com"
  }
}

Compliance Mapping

Each scan evaluates TLS configuration against transport encryption requirements for PCI DSS 4.0, NIST SP 800-52r2, and HIPAA. These are transport-layer checks only — passing means "meets transport encryption requirements for <framework>", not full compliance with the framework itself.

Each finding has a status: pass, fail, or warn. A framework meets_requirements when all findings are pass or warn (warnings don't cause failure).

Rate Limit Headers

Every response includes standard rate limit headers:

No Auth Required

No API keys. No accounts. No tracking. Just data.