TCPLab TCPLab

SSL Certificate Check API

Last updated: 2026-10-19

POST /api/v2/tls/check with Content-Type: application/json

Completes a real TLS handshake with the target and returns its certificate and connection details. Only the handshake is performed — no HTTP request is sent and no page content is downloaded. Base URL, response format and rate limits are shared across endpoints — see the API documentation.

Parameter Description
host Domain or IP literal (IPv4, or IPv6 with or without brackets). Required. Pass a host, not a URL: strip the scheme, path and query first. Unicode domains are converted to punycode.
port TCP port, 1–65535; defaults to 443.

Domains are resolved through A and AAAA queries (IPv4 first). Up to two connectable addresses are tried, sharing an 8-second total budget; a single handshake times out after 5 seconds and DNS resolution after 3 seconds. Private, loopback, link-local and reserved addresses are never probed. An IP target is connected to directly.

The handshake completes even when the certificate is invalid, so a successful response means TLS was established — check validation for the certificate verdict.

Example:

curl -X POST "https://tcp.lc/api/v2/tls/check" \
  -H "Content-Type: application/json" \
  -d '{"host":"example.com","port":443}'

Response data fields:

Field Description
host Normalized target: a domain (punycode for IDNs) or an IP literal.
targetType domain or ip.
port Port that was checked.
ip Address that actually completed the handshake.
addresses Resolved connectable addresses, IPv4 first; private and reserved addresses are filtered out. For an IP target this is the target itself.
elapsed Server-side time for the whole check, in milliseconds.
connection Negotiated TLS details; see below.
certificate Certificate details; see below.
validation Certificate verdict; see below.

connection fields:

Field Description
version Negotiated TLS version, such as TLSv1.3 or TLSv1.2.
cipher Negotiated cipher suite, such as TLS_AES_128_GCM_SHA256.
forwardSecrecy true when the connection uses forward secrecy (all TLS 1.3 suites, or ECDHE/DHE on older versions).
alpn ALPN result (h2 or http/1.1), or null when the server ignored ALPN.
http2 true when ALPN selected h2.

certificate fields:

Field Description
subject Certificate subject as a single-line RDN string, usually starting with CN=.
issuer Issuing certificate authority, also as an RDN string.
validFrom Start of the validity period, ISO 8601.
validTo End of the validity period, ISO 8601.
daysRemaining Days until validTo, rounded down; negative when the certificate has expired.
san DNS names from the subject alternative name extension, wildcards preserved.
publicKeyAlgorithm RSA, RSA-PSS, ECDSA, Ed25519, Ed448 or DSA.
publicKeyBits Key size, such as 2048 or 256; null when unknown.
publicKeyCurve Named curve for EC keys, such as prime256v1; null otherwise.

validation fields:

Field Description
valid true when the chain is trusted, the certificate is within its validity period and it matches the hostname.
issues Problem categories; empty when valid is true.
errorCode Raw OpenSSL/Node error code, such as CERT_HAS_EXPIRED, for troubleshooting; null when valid.

issues values:

Value Meaning
expired The certificate has expired.
notYetValid The validity period starts in the future.
hostname The certificate does not match the requested hostname.
selfSigned The certificate is self-signed.
untrusted The chain is not trusted, for example a missing intermediate certificate or an unknown issuer.
unknown Validation failed for another reason.

Example:

{
  "code": 200,
  "msg": "ok",
  "data": {
    "host": "example.com",
    "targetType": "domain",
    "port": 443,
    "ip": "93.184.215.14",
    "addresses": ["93.184.215.14", "2606:2800:21f:cb07:6820:80da:af6b:8b2c"],
    "elapsed": 182,
    "connection": {
      "version": "TLSv1.3",
      "cipher": "TLS_AES_128_GCM_SHA256",
      "forwardSecrecy": true,
      "alpn": "http/1.1",
      "http2": false
    },
    "certificate": {
      "subject": "CN=example.com",
      "issuer": "C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1",
      "validFrom": "2026-01-01T00:00:00.000Z",
      "validTo": "2027-01-01T23:59:59.000Z",
      "daysRemaining": 74,
      "san": ["example.com", "www.example.com"],
      "publicKeyAlgorithm": "RSA",
      "publicKeyBits": 2048,
      "publicKeyCurve": null
    },
    "validation": {
      "valid": true,
      "issues": [],
      "errorCode": null
    }
  }
}

An invalid certificate is not an API error. The response is still code: 200; the verdict is in validation. Only that object is shown here:

{
  "code": 200,
  "msg": "ok",
  "data": {
    "validation": {
      "valid": false,
      "issues": ["expired"],
      "errorCode": "CERT_HAS_EXPIRED"
    }
  }
}

Errors

Failures use code: -1000, with msg set to a stable identifier. data.args may carry details.

msg Meaning
api.param.host.invalid host is missing or cannot be parsed as a domain or IP literal. data.args.host carries the input.
api.param.port.invalid The port is not an integer between 1 and 65535. data.args.port carries it.
api.param.host.private Every resolved address is private or reserved, so it cannot be probed.
api.notfound.domain The domain does not exist (NXDOMAIN). data.args.name carries it.
api.notfound.address The domain has no A or AAAA records. data.args.name carries it.
api.upstream.timeout DNS resolution timed out.
api.upstream.error DNS resolution failed for another reason.
api.upstream.tls.timeout The TLS handshake timed out.
api.upstream.tls.refused The connection was refused — nothing is listening on the port, or TLS is not enabled.
api.upstream.tls.handshake The TLS handshake failed; the server may not support HTTPS or its TLS configuration is incompatible.
api.upstream.tls.error The handshake failed for another network reason.
api.rate.limitedDaily The daily quota is exhausted. A Retry-After header is included.
api.server.internal Server or configuration error.

Example:

{
  "code": -1000,
  "msg": "api.param.host.private",
  "data": null
}

Notes

  • For an IP target, hostname matching is skipped because an IP may not appear in the certificate SAN. Expiry and chain trust are still verified.
  • Behind a CDN or a domain with several addresses, different edge nodes can serve different certificates. ip reports the address that was actually used.
  • validation covers chain trust, validity dates and hostname matching. Revocation (CRL/OCSP) is not checked.
  • Only the TLS handshake is made; the server never sends an HTTP request.

Rate limits and caching

Rate limiting is per client IP: 10 requests per minute and 100 per day. Every request counts, including failed checks. The daily quota resets at 00:00 UTC+8. When the per-minute limit is exceeded, the endpoint returns api.rate.limited; when the daily quota is exhausted, it returns api.rate.limitedDaily. Both include a Retry-After header in seconds.

Successful responses carry Cache-Control: public, max-age=300, s-maxage=600. Error responses are sent with Cache-Control: no-store.