TLS Inspector API

Base URL: https://tls.netray.info

Full TLS handshake and certificate chain analysis. Connects to the target, inspects the certificate chain, checks DANE/TLSA and CAA records, validates OCSP stapling and CT SCTs, tests HSTS, and runs 15 graded quality checks.

See also: interactive API reference (auto-generated OpenAPI)

Endpoints

GET /api/inspect?host=

Inspect a host's TLS configuration. Returns a synchronous JSON response.

curl -s 'https://tls.netray.info/api/inspect?host=example.com' | jq .

POST /api/inspect

Same inspection via POST body.

curl -s -X POST https://tls.netray.info/api/inspect \
  -H 'Content-Type: application/json' \
  -d '{"host": "example.com"}' | jq .

Custom Port

Append a port number to inspect non-standard TLS ports:

curl -s 'https://tls.netray.info/api/inspect?host=example.com:8443' | jq .

Multi-Port Inspection

Inspect multiple ports in a single request:

curl -s 'https://tls.netray.info/api/inspect?host=example.com:443,8443' | jq .

Response Structure

The response contains several top-level sections:

{
  "summary": {
    "host": "example.com",
    "verdict": "Pass",
    "grade": "A",
    ...
  },
  "ports": [
    {
      "port": 443,
      "ips": [
        {
          "ip": "93.184.215.14",
          "tls_version": "TLSv1.3",
          "cipher_suite": "TLS_AES_256_GCM_SHA384",
          "certificate": {
            "subject": "CN=example.com",
            "issuer": "CN=DigiCert TLS RSA SHA256 2020 CA1",
            "not_before": "2024-01-15T00:00:00Z",
            "not_after": "2025-02-14T23:59:59Z",
            "serial": "0A:1B:2C:...",
            "sans": ["example.com", "www.example.com"],
            "signature_algorithm": "SHA256withRSA",
            "key_type": "RSA 2048"
          },
          "chain": [
            {"subject": "CN=example.com", "issuer": "CN=DigiCert TLS RSA SHA256 2020 CA1"},
            {"subject": "CN=DigiCert TLS RSA SHA256 2020 CA1", "issuer": "CN=DigiCert Global Root G2"}
          ],
          "ocsp": {
            "stapled": true,
            "status": "good"
          },
          "scts": [
            {"log": "Google Argon", "timestamp": "2024-01-15T12:00:00Z"}
          ],
          "enrichment": {
            "asn": 64496,
            "isp": "Example Networks",
            "country": "US"
          }
        }
      ]
    }
  ],
  "dns": {
    "caa": [
      {"flag": 0, "tag": "issue", "value": "digicert.com"}
    ],
    "tlsa": [],
    "dane_valid": false
  },
  "quality": {
    "verdict": "Pass",
    "grade": "A",
    "checks": [
      {"name": "certificate_validity", "status": "pass", "detail": "Certificate valid for 396 days"},
      {"name": "chain_completeness", "status": "pass", "detail": "Full chain provided"},
      {"name": "san_quality", "status": "pass", "detail": "SAN covers primary domain"},
      {"name": "aia_reachability", "status": "pass", "detail": "AIA OCSP responder reachable"},
      ...
    ]
  },
  "hsts": {
    "enabled": true,
    "max_age": 31536000,
    "include_subdomains": true,
    "preloaded": false
  }
}

Quality Checks

The quality.checks array contains up to 15 graded checks. Each check has a status of pass, warn, or fail:

CheckWhat It Tests
certificate_validityCertificate is not expired and not expiring soon
chain_completenessFull chain is served (no missing intermediates)
chain_orderCertificates are in correct order
signature_algorithmStrong signature algorithm (no SHA-1)
key_strengthAdequate key size (RSA >= 2048, ECDSA >= 256)
tls_versionTLS 1.2 or 1.3 (no SSLv3, TLS 1.0/1.1)
san_qualitySAN list covers the queried hostname
aia_reachabilityAIA OCSP and CA Issuers URLs are reachable
ocsp_staplingOCSP stapling is present and valid
ct_sctsCertificate Transparency SCTs are present
dane_complianceTLSA record matches certificate (if TLSA exists)
caa_complianceIssuer is authorized by CAA records
hstsHSTS header is present with adequate max-age
redirectHTTP redirects to HTTPS
certificate_transparencyCertificate appears in CT logs

Useful One-Liners

# Get the overall grade
curl -s 'https://tls.netray.info/api/inspect?host=example.com' | jq '.quality.grade'

# Check certificate expiry date
curl -s 'https://tls.netray.info/api/inspect?host=example.com' \
  | jq '.ports[0].ips[0].certificate.not_after'

# List all SANs
curl -s 'https://tls.netray.info/api/inspect?host=example.com' \
  | jq '.ports[0].ips[0].certificate.sans[]'

# Check for failing quality checks
curl -s 'https://tls.netray.info/api/inspect?host=example.com' \
  | jq '[.quality.checks[] | select(.status == "fail")]'

# Verify DANE/TLSA compliance
curl -s 'https://tls.netray.info/api/inspect?host=example.com' \
  | jq '.dns.dane_valid'

# CI gate: fail if grade is below A
curl -sf 'https://tls.netray.info/api/inspect?host=example.com' \
  | jq -e '.quality.verdict == "Pass"'

Multi-IP Fan-Out

When a domain resolves to multiple IPs, tlsight inspects each one independently. The ports[].ips[] array contains per-IP results. If an IP is unreachable, it is included with an error rather than silently dropped (cap-and-warn graceful degradation).

Rate Limits

Per-IP and per-target GCRA rate limiting. The cost of a request is:

cost = number_of_ports * number_of_inspected_ips

Inspecting example.com:443,8443 where the domain resolves to 3 IPs costs 6 (2 ports x 3 IPs).

When rate-limited, you receive a 429 response with a Retry-After header.

Errors

{
  "error": {
    "code": "bad_request",
    "message": "Missing required parameter: host"
  }
}

Common error codes:

CodeMeaning
bad_requestMissing or invalid host parameter
rate_limitedToo many requests; check Retry-After
connection_failedCould not establish TLS connection to target
internal_errorServer error; include X-Request-Id in reports