本文へスキップ
ecdsa.com

Domain health

TLS signature-health grade for a domain

GEThttps://ecdsa.com/api/v1/health/{domain}

Connects to the domain on port 443, examines the served certificate chain, key and signature algorithms, protocol versions and lifetimes, and returns a letter grade with findings, plus the leaf certificate's expiry and key algorithm as structured fields. Results are cached for 1 hour. Only public DNS hostnames are accepted — IP addresses, single-label names and private/reserved addresses are refused. Extra rate limit: 10 requests/minute per IP. A fresh scan can take several seconds.

API キー
任意(キーには scan スコープが必要)
キー使用時のクォータ消費
呼び出しごとに 5 ユニット
レート制限
IP あたり毎分 60 リクエスト、スキャンは別途毎分 10 回
スキャン枠
同一ホストへの実際のスキャンは 10 分あたり 6 回まで、全体では毎分 300 回までで、全利用者で共有します。キャッシュからのレスポンスは枠を消費しません

リクエスト

パスパラメーター

フィールド型必須説明
domainstringはい

Public DNS hostname, e.g. "github.com".

レスポンス

200Health grade, findings and the served leaf certificate.

フィールド型必須説明
domainstringはい
gradeobjectはい
grade.letterstringはい
  • "A+"、"A"、"B"、"C"、"D"、または"F" のいずれか
grade.scoreintegerはい
  • 0 以上
  • 100 以下
findingsHealthFinding[]はい
scannedAtstringはい
  • 形式 date-time
cachedbooleanはい

Best-effort: true when the result came from the 1-hour cache.

cacheTtlSecondsintegerはい
  • 常に 3600
reportUrlstringはい

Human-readable report for the same domain.

  • 形式 uri
certificateHealthCertificate | nullはい

null only when the report carries no certificate.

ヘッダー: X-Request-Id · X-RateLimit-Limit · X-RateLimit-Remaining · X-RateLimit-Reset · X-Quota-Limit · X-Quota-Remaining · X-Quota-Reset

ステータス意味コード
400Bad request. Input limits: a request body of at most 100 KB (a larger one is answered with 413) and arrays and objects nested at most 64 levels deep, JSON documents inside string fields included.
401Unauthorized.
403Forbidden.
404Not found.
405Method not allowed.
429Too many requests.
500Internal server error.
502Bad gateway.
503Service unavailable.
504Gateway timeout.

エラーのレスポンスにはすべて JSON エンベロープが含まれます。各コードの意味と対処法はエラー一覧表で確認できます。

例

A public domain

curl
curl -sS 'https://ecdsa.com/api/v1/health/github.com'
JavaScript (fetch)
const response = await fetch("https://ecdsa.com/api/v1/health/github.com");
console.log(response.status, await response.json());
Python (httpx)
import httpx

response = httpx.get("https://ecdsa.com/api/v1/health/github.com", timeout=30.0)
print(response.status_code, response.json())
レスポンス 200
{
  "domain": "github.com",
  "grade": {
    "letter": "A+",
    "score": 100
  },
  "findings": [
    {
      "id": "pqc-migration-ahead",
      "severity": "info",
      "title": "Classical algorithm — post-quantum migration ahead",
      "detail": "ECDSA P-256 is a sound choice today. It is, however, quantum-vulnerable: NIST IR 8547 (draft) plans to disallow classical signature algorithms — ECDSA, EdDSA and RSA — after 2035; at this key size there is no earlier 2030 milestone — that step covers only 112-bit parameter sets such as RSA-2048. No penalty and no emergency — but certificate rotation is the easy part; knowing everywhere else your systems sign is the real migration work."
    },
    {
      "id": "key-modern",
      "severity": "ok",
      "title": "Modern signature key (ECDSA P-256)",
      "detail": "ECDSA P-256 gives compact keys and signatures at full strength — the current best practice for TLS server certificates."
    },
    {
      "id": "cert-valid",
      "severity": "ok",
      "title": "Within validity period",
      "detail": "Valid until 2026-11-29 — 41 days remaining."
    },
    {
      "id": "cert-short-lifetime",
      "severity": "ok",
      "title": "Short certificate lifetime (90 days)",
      "detail": "Lifetimes of 90 days or less are the signature of automated issuance and rotation (ACME et al.) — exactly the posture the shrinking CA/Browser Forum limits are pushing everyone toward. Well done."
    },
    {
      "id": "legacy-tls-refused",
      "severity": "ok",
      "title": "Legacy TLS refused",
      "detail": "Handshakes capped at TLS 1.1 were rejected — the deprecated protocol versions are switched off."
    },
    {
      "id": "tls13",
      "severity": "ok",
      "title": "TLS 1.3 negotiated",
      "detail": "The handshake settled on TLS 1.3 with TLS_AES_128_GCM_SHA256 — the current protocol generation, with a cleaner handshake and only AEAD ciphers."
    },
    {
      "id": "chain-complete",
      "severity": "ok",
      "title": "Certificate chain complete (as served)",
      "detail": "Every issuer → subject link matches and the chain ends at a self-signed root (chain as served)."
    }
  ],
  "scannedAt": "2026-10-20T07:14:02.839Z",
  "cached": true,
  "cacheTtlSeconds": 3600,
  "reportUrl": "https://ecdsa.com/health/github.com",
  "certificate": {
    "notAfter": "2026-11-29T23:59:59.000Z",
    "daysRemaining": 41,
    "keyAlgorithm": "ECDSA",
    "curve": "P-256"
  }
}

この例に対する API のレスポンスです。2026年10月20日にこのページ用に取得したもので、含まれる相対時間や日数はその日を基準にしています。 github.com のスキャン結果は、その日に本番環境で記録したものです。実際に呼び出すと、新たにスキャンするか、1 時間のキャッシュからレスポンスを返します。

エラーコード

コードステータス意味
invalid_json400The body is not valid JSON or not a JSON object; or the input nests arrays and objects more than 64 levels deep (JSON documents inside string fields count too), or is too complex to inspect for private keys.
private_key_rejected400The request contains private-key material (a PEM PRIVATE KEY block, an OpenSSH, SSH2 or PuTTY private key, or a JWK with "d"). Never send private keys anywhere.
invalid_domain400Not a public DNS hostname (IP addresses, single-label names and paths are refused).
scan_dns_error400The domain does not resolve in public DNS.
scan_private_address400The domain resolves (at least partly) to a private or reserved address.
unauthorized401The Authorization or X-API-Key header is malformed, the API key is not valid (wrong checksum, unknown, revoked or expired), or the operation needs a key.
forbidden_scope403The API key is valid but lacks a scope this operation requires; the message names it.
not_found404No operation exists at this path.
method_not_allowed405The path exists but does not accept this HTTP method; see the Allow header.
rate_limited429Too many requests — see Retry-After.
quota_exceeded429A daily or monthly quota of the API key's account is used up. X-Quota-Reset (and Retry-After) say when it starts over; retrying earlier cannot succeed.
internal_error500Unexpected server error.
scan_unreachable502The domain refused or dropped the connection on port 443.
scan_tls_error502The TLS handshake failed or presented no usable certificate.
service_unavailable503API keys cannot be verified right now (the key store is unreachable); retry shortly.
scan_timeout504The scan did not finish in time.

スキーマ

HealthFinding

フィールド型必須説明
idstringはい

Stable identifier, e.g. "cert-expired" or "tls13".

severitystringはい
  • "critical"、"warn"、"info"、または"ok" のいずれか
titlestringはい
detailstringはい

HealthCertificate

The served leaf certificate, as structured fields.

フィールド型必須説明
notAfterstringはい

End of the leaf certificate's validity.

  • 形式 date-time
daysRemainingintegerはい

Whole days from scannedAt until notAfter, rounded up; zero or negative once expired.

keyAlgorithmstringはい

Public-key algorithm of the leaf certificate: ECDSA, RSA, Ed25519, Ed448, an ML-DSA or SLH-DSA parameter set, or the scanner's label for anything else.

curvestring | nullはい

Named curve of an ECDSA key ("P-256", "P-384", …); null otherwise.

Error

The error envelope of every non-2xx response.

フィールド型必須説明
errorobjectはい
error.codestringはい

Machine-readable error code. Each response lists the codes it can carry; new codes may be added within v1, so treat an unknown code by its HTTP status.

error.messagestringはい

Human-readable explanation (English).

error.requestIdstringいいえ

The X-Request-Id of this request — quote it when reporting a problem. Sent since v1.1.

error.detailobjectいいえ

Structured context for the error, such as the offending field; omitted when there is none.

  • メンバー名は任意
error.docsstringいいえ

Where the error codes are explained. Sent since v1.1.

  • 形式 uri

すべての操作は API リファレンスに掲載しています。