API REFERENCE · GET · STABLE

SSL Certificate Chain API — /api/v1/security/ssl-chain

Full certificate chain with each link tagged `EndEntity | Intermediate | Root`. Same live TLS handshake as `/ssl-info`, minimal payload — chain plus any chain issues detected (missing intermediate, broken link, expired non-root, weak signature). Use this when you only need chain-of-trust data.

01 · OVERVIEW

What this endpoint returns

Chain-only slice of the full SSL/TLS report — same live handshake, just narrower. Each cert is typed and issue-detected.

  • Method GET
  • Path /api/v1/security/ssl-chain
  • Stability STABLE
  • Version v2026-07-18
  • Summary Full certificate chain (leaf → intermediates → root) with type tags + chain-issue detection.
  • Related Use `/security/ssl-info` for the full posture report (grade, HSTS, CAA, AI diagnosis). This endpoint is the chain-only slice.
02 · PARAMETERS

Request parameters

Pass as query-string parameters. Only `domain` is required.

  • domain (required) — string Hostname or URL (scheme/path stripped).
  • raw — boolean, default false Include each cert as PEM (`chain[].pem`). Adds ~4 KB per link.
03 · RESPONSE

Response schema

Wrapped in `{ success: true, data: {...} }`. The data payload has three top-level fields.

  • data.found — boolean True when the handshake succeeded.
  • data.domain — string Normalised hostname.
  • data.chain — array<object> Ordered from position 0 (End-Entity leaf) up to Root CA. See per-cert breakdown below.
  • data.chain_issues — array<object> Detected chain problems with `severity: critical | warning | info` and human-readable `message`. Examples: 'Server sent no intermediate certificate', 'Chain link broken at position 1', 'Intermediate certificate expires in 4 days'.
  • chain[].position — integer 0 = leaf, increments up the chain to the root.
  • chain[].type — string `EndEntity` (position 0), `Intermediate` (CA cert not self-signed), `Root` (self-signed CA cert).
  • chain[].status — string `Valid` or `Invalid` (past valid_to).
  • chain[].subject — object `{common_name, organization, organizational_unit, country, state, locality, email}` — decoded X.500 DN.
  • chain[].issuer — object Same shape as `subject`.
  • chain[].validity — object `{from, to, days, days_remaining, is_expired, age_days}`.
  • chain[].serial_number — string Uppercase hex.
  • chain[].fingerprint / fingerprint256 — string SHA-1 + SHA-256 colon-separated.
  • chain[].public_key — object `{type, bits, curve, strength, label}`.
  • chain[].signature_algorithm — object `{oid, name, hash, weak}` — weak flag = SHA-1/MD5-based sig.
  • chain[].key_usage — array<string> Extended Key Usage OIDs.
  • chain[].subject_alt_names — array<string> SANs (only meaningful on the leaf; usually empty on CA certs).
  • chain[].is_ca / is_self_signed / is_wildcard — booleans Structural flags.
  • chain[].pem — string (when raw=true) PEM-encoded cert body.
04 · EXAMPLE

Example response

Abridged shape for `?domain=github.com`.

Sample response
{
  "success": true,
  "data": {
    "found": true,
    "domain": "github.com",
    "chain": [
      {
        "position": 0,
        "type":     "EndEntity",
        "status":   "Valid",
        "subject":  { "common_name": "github.com" },
        "issuer":   { "common_name": "Sectigo Public Server Authentication CA DV E36", "organization": "Sectigo Limited" },
        "validity": { "from": "2026-07-03T…", "to": "2026-10-01T…", "days_remaining": 75, "is_expired": false },
        "serial_number":  "72010E03F4A067FE4E796266430718F6",
        "fingerprint256": "17:F8:FD:2E:…",
        "public_key":     { "type": "EC", "bits": 256, "curve": "prime256v1", "label": "ECDSA P-256", "strength": "strong" },
        "signature_algorithm": { "name": "SHA256-RSA", "weak": false }
      },
      {
        "position": 1,
        "type":     "Intermediate",
        "status":   "Valid",
        "subject":  { "common_name": "Sectigo Public Server Authentication CA DV E36" },
        "issuer":   { "common_name": "Sectigo Public Server Authentication Root E46" }
      },
      {
        "position": 2,
        "type":     "Intermediate",
        "status":   "Valid",
        "subject":  { "common_name": "Sectigo Public Server Authentication Root E46" },
        "issuer":   { "common_name": "USERTrust ECC Certification Authority" }
      },
      {
        "position": 3,
        "type":     "Root",
        "status":   "Valid",
        "subject":  { "common_name": "USERTrust ECC Certification Authority" },
        "issuer":   { "common_name": "USERTrust ECC Certification Authority" }
      }
    ],
    "chain_issues": []
  }
}
05 · CHAIN ISSUES

Detected chain problems

`data.chain_issues[]` is populated when any of the following are detected. Empty array = healthy chain.

  • Server sent no intermediate certificate (warning) chain.length === 1. Browsers work around via AIA, but Java + curl + older Android will fail the handshake.
  • Chain link broken at position N (warning) Cert N's `issuer.common_name` doesn't match cert N+1's `subject.common_name`. Usually means the chain is out of order or contains a stray cert.
  • Certificate expires in K days (warning / critical) Any cert in the chain within 30 days of expiry. `< 7 days` = critical, `< 30 days` = warning. Applies to intermediates too — a fresh leaf can't save you if the intermediate expired yesterday.
  • Certificate has expired (critical) `validity.is_expired: true`. Chain is broken regardless of leaf validity.
  • Weak signature: NAME (critical / info) SHA-1 or MD5-based signature. Critical for leaf + intermediate certs; info-level for roots (self-signed, not verified by anyone else).
06 · CURL EXAMPLES

One-line invocations

Chain length + types
curl -s 'https://api.domainscan.in/v1/security/ssl-chain?domain=github.com' \
  -H 'Origin: https://domainscan.in' | jq '.data.chain | map(.type)'
# → ["EndEntity","Intermediate","Intermediate","Root"]
Alert on any chain issue
issues=$(curl -s 'https://api.domainscan.in/v1/security/ssl-chain?domain=github.com' \
  -H 'Origin: https://domainscan.in' | jq '.data.chain_issues | length')
if [ "$issues" -gt 0 ]; then
  echo "⚠️  Chain has $issues issue(s) — inspect the endpoint output"
fi
07 · ERRORS

Error codes

  • 200 + data.found=false TLS handshake failed (host down, port 443 closed, TCP timeout). `data.chain` is `[]`.
  • 400 VALIDATION_FAILED `domain` missing or malformed.
  • 401 / 403 Auth or origin check failed — see /security/ssl-info error docs.
08 · BEST PRACTICES

Integration tips

  • Use this when `/ssl-info` reports a valid leaf but browsers still complain. Most common cause is a missing intermediate — chain.length === 1 + `chain_issues` will name the exact problem.
  • Watch intermediate expiry, not just the leaf. Intermediates rotate less often but do rotate — an intermediate expiring next week breaks every downstream cert even if the leaf is fresh.
  • Prefer `/ssl-info` for anything but chain diagnosis. Same underlying handshake, but with grade + HSTS + CAA + AI. This endpoint exists for narrow chain-only integrations.