SSL Monitoring API: Cert Expiry, Issuer & Chain (2026)

June 5, 2026 · 10 min read

An SSL monitoring API is the difference between knowing a certificate expires next Tuesday and finding out from a customer ticket at 3 AM. The job is small but unforgiving: every public TLS cert your organization owns needs an expiry date that is somewhere in the future, an issuer that is still trusted, a chain that resolves cleanly on every client, and a key that meets your security baseline.

Doing this with openssl s_client works for one server. Doing it for fifty domains, in five regions, on a daily cron, while also alerting Slack and gating CI deploys, needs structured JSON over HTTP. That is what an SSL monitoring API gives you.

This guide walks through what an SSL monitoring API should return, how the DetectZeStack /certificate/check endpoint is shaped, and three patterns for wiring it into real workflows: daily expiry alerts, CI/CD TLS gates, and bulk monitoring across hundreds of domains.

Why You Need an SSL Monitoring API in 2026

Three things changed about certificate operations in the last few years, and they make API-driven monitoring not optional.

Certificate lifetimes are shrinking. Let's Encrypt has always issued 90-day certs. The CA/Browser Forum has been steadily ratcheting maximum lifetimes downward, and most public CAs now issue 397-day certs as the ceiling. Shorter validity means more renewals, more automation, and more opportunities for a renewal to silently fail. The window between "all green" and "expired in production" can be a single missed cron run.

Multi-SAN deployments are normal. A single certificate often covers app.example.com, api.example.com, www.example.com, and a wildcard for staging. When the SAN list changes, you want to detect it. Manual tracking does not scale; only an API call that returns san_domains as a parsable array does.

Trust stores update without your knowledge. Browsers and OS vendors distrust CAs periodically. A certificate that was valid yesterday can be untrusted on iOS tomorrow if the issuing intermediate gets pulled. An API that returns the full chain lets you check whether every intermediate is still trusted, before users see a connection error.

What an SSL Monitoring API Should Return

The minimum useful response from an SSL monitoring API is structured JSON that answers four questions: when does it expire, who issued it, what does it cover, and is the chain complete. Anything less than that and you are still going to shell out to OpenSSL when something goes wrong.

Expiry, Issuer, Subject, and SAN Coverage

The four fields you will read on every check:

Chain Validation and Intermediate Certs

The leaf certificate is rarely the whole story. Browsers and clients need the intermediate certificates too, and if your server is misconfigured to omit them, the connection fails in unpredictable ways. A monitoring API should return the chain so you can verify it without a second tool. Look for an array where each entry has at least subject, issuer, not_after, and an is_ca boolean.

Key Algorithm, Bit Length, and Signature Strength

If your security policy says "no RSA below 2048 bits" or "ECDSA preferred for all customer-facing endpoints," you need public_key.algorithm and public_key.bit_length in the response. Same for signature_algorithm: SHA-1 has been deprecated for years, but legacy renewals still happen.

DetectZeStack SSL Monitoring API: Endpoint and Fields

DetectZeStack's GET /certificate/check endpoint performs a live TLS handshake on port 443 and returns the certificate, the chain, and the TLS connection details as a single JSON payload. It is part of the same API surface that handles tech stack detection, DNS intelligence, and security headers, so the same RapidAPI key works for all of them and they share one monthly quota.

Live curl Example Against /demo/certificate

You can try the endpoint without an API key against the demo URL. This is the same handler as the production endpoint, just unauthenticated and rate-limited per IP:

curl -s "https://detectzestack.com/demo/certificate?url=github.com" | python3 -m json.tool

For production use, get a free RapidAPI key (no credit card needed) and call the authenticated endpoint:

curl -s "https://detectzestack.p.rapidapi.com/certificate/check?url=github.com" \
  -H "x-rapidapi-key: YOUR_API_KEY" \
  -H "x-rapidapi-host: detectzestack.p.rapidapi.com" | python3 -m json.tool

A truncated response looks like this:

{
  "domain": "github.com",
  "ip": "140.82.121.3",
  "port": 443,
  "has_tls": true,
  "tls": {
    "version": "TLS 1.3",
    "cipher_suite": "TLS_AES_128_GCM_SHA256",
    "negotiated_protocol": "h2"
  },
  "certificate": {
    "subject": {
      "common_name": "github.com",
      "organization": ["GitHub, Inc."]
    },
    "issuer": {
      "common_name": "Sectigo ECC Domain Validation Secure Server CA",
      "organization": ["Sectigo Limited"]
    },
    "not_before": "2026-02-26T00:00:00Z",
    "not_after": "2027-02-26T23:59:59Z",
    "days_remaining": 266,
    "is_expired": false,
    "signature_algorithm": "ECDSA-SHA384",
    "public_key": {
      "algorithm": "ECDSA",
      "bit_length": 256
    },
    "san_domains": ["github.com", "www.github.com"],
    "key_usage": ["Digital Signature"],
    "ext_key_usage": ["Server Authentication", "Client Authentication"]
  },
  "chain": [
    {
      "subject": "Sectigo ECC Domain Validation Secure Server CA",
      "issuer": "USERTrust ECC Certification Authority",
      "is_ca": true,
      "not_after": "2030-12-31T23:59:59Z",
      "signature_algorithm": "ECDSA-SHA384"
    }
  ],
  "response_ms": 187
}

Field-by-Field Breakdown of the JSON Response

Field Type Purpose
domain string Domain that was checked
ip string Resolved IP for the TLS connection
has_tls boolean Whether the handshake succeeded at all
tls.version string Negotiated version: TLS 1.0, 1.1, 1.2, or 1.3
tls.cipher_suite string Negotiated cipher (e.g. TLS_AES_128_GCM_SHA256)
certificate.days_remaining integer Days until not_after
certificate.is_expired boolean True if now > not_after
certificate.san_domains string[] Subject Alternative Names (DNS)
certificate.public_key.algorithm string RSA, ECDSA, or Ed25519
certificate.public_key.bit_length integer Key size in bits
chain array Intermediate and root certs in the path
response_ms integer Handshake time in milliseconds

One quota, many endpoints. The same API key works for /certificate/check, /analyze (tech detection), /dns (DNS intelligence), and /security (headers). One $9/month plan covers daily SSL checks on roughly 33 domains alongside any other monitoring you want.

Building a Cert Expiry Alerting Workflow

The simplest production use case: run a daily cron, hit /certificate/check for each domain you care about, and post a Slack message when days_remaining drops below a threshold.

Cron + days_remaining Threshold Pattern

The pattern is three nested decisions: hard-fail if the cert is already expired, warn at 30 days, log at 60. You can tune the thresholds to your renewal cadence.

#!/bin/bash
# ssl-monitor.sh — run from cron, e.g. 0 8 * * *
set -euo pipefail

DOMAINS=("app.example.com" "api.example.com" "billing.example.com")
API_KEY="${RAPIDAPI_KEY:?set RAPIDAPI_KEY}"
SLACK_WEBHOOK="${SLACK_WEBHOOK:?set SLACK_WEBHOOK}"

for domain in "${DOMAINS[@]}"; do
  RESULT=$(curl -fsS "https://detectzestack.p.rapidapi.com/certificate/check?url=$domain" \
    -H "x-rapidapi-key: $API_KEY" \
    -H "x-rapidapi-host: detectzestack.p.rapidapi.com")

  DAYS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['certificate']['days_remaining'])")
  EXPIRED=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['certificate']['is_expired'])")
  ISSUER=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['certificate']['issuer'].get('common_name','?'))")

  if [[ "$EXPIRED" == "True" ]]; then
    MSG=":rotating_light: CRITICAL: $domain SSL cert is EXPIRED (issuer: $ISSUER)"
  elif [[ "$DAYS" -lt 14 ]]; then
    MSG=":warning: URGENT: $domain expires in $DAYS days (issuer: $ISSUER)"
  elif [[ "$DAYS" -lt 30 ]]; then
    MSG=":bell: Reminder: $domain expires in $DAYS days"
  else
    continue
  fi

  curl -fsS -X POST "$SLACK_WEBHOOK" \
    -H "Content-Type: application/json" \
    -d "{\"text\":\"$MSG\"}"
done

Wiring Alerts to Slack or Email

The script above posts to a Slack incoming webhook, but the JSON shape is portable. Pipe the same fields into PagerDuty's Events API, send them through SendGrid for email, or push them into a Datadog metric. The point is that days_remaining as a typed integer means you write the alert logic once and never parse a date string again.

Auditing the Certificate Chain for Trust Issues

Expiry is the headline metric, but chain misconfiguration is the silent killer. A server can serve a leaf certificate that is technically valid, while omitting the intermediate the client needs to build a trust path. Some clients (modern browsers) will compensate by fetching the intermediate themselves; others (older Java, some embedded devices, some mobile clients) will just fail.

The chain array in the response is how you catch this. A correctly configured server returns at least one intermediate; if the array has only the leaf, your server is incomplete. You can audit this in Python:

import requests

API_KEY = "your-rapidapi-key"
DOMAINS = ["app.example.com", "api.example.com", "cdn.example.com"]

headers = {
    "x-rapidapi-key": API_KEY,
    "x-rapidapi-host": "detectzestack.p.rapidapi.com",
}

for domain in DOMAINS:
    r = requests.get(
        f"https://detectzestack.p.rapidapi.com/certificate/check?url={domain}",
        headers=headers,
        timeout=15,
    )
    data = r.json()
    chain = data.get("chain", [])
    cert = data.get("certificate", {})

    issues = []
    if not chain:
        issues.append("chain is empty (no intermediates served)")
    for link in chain:
        if "SHA1" in link.get("signature_algorithm", "").upper():
            issues.append(f"intermediate uses SHA-1: {link['subject']}")
    if cert.get("public_key", {}).get("algorithm") == "RSA" and cert.get("public_key", {}).get("bit_length", 0) < 2048:
        issues.append("RSA key below 2048 bits")

    status = "PASS" if not issues else "FAIL"
    print(f"{domain:30s} {status}")
    for i in issues:
        print(f"  - {i}")

This catches three of the most common chain problems: missing intermediates, deprecated signature algorithms, and weak keys. Add SAN-coverage checks (every domain you expect should appear in san_domains) and you have a fleet-wide policy audit in 30 lines of code.

Bulk Monitoring with /analyze/batch

For one-off cert sweeps across a list of domains, the authenticated POST /analyze/batch endpoint accepts an array of URLs and runs detection in parallel. It is designed for tech stack scans, but the same batch model works if you want a single round-trip for tech and TLS data together.

If you specifically want certificate-only data at high volume, the cleanest pattern is just a loop of /certificate/check calls with reasonable concurrency:

import concurrent.futures
import requests

API_KEY = "your-rapidapi-key"
DOMAINS = open("domains.txt").read().splitlines()

headers = {
    "x-rapidapi-key": API_KEY,
    "x-rapidapi-host": "detectzestack.p.rapidapi.com",
}

def check(domain):
    r = requests.get(
        f"https://detectzestack.p.rapidapi.com/certificate/check?url={domain}",
        headers=headers, timeout=15,
    )
    d = r.json()
    cert = d.get("certificate", {})
    return {
        "domain": domain,
        "days": cert.get("days_remaining", -1),
        "expired": cert.get("is_expired", True),
        "issuer": cert.get("issuer", {}).get("common_name", "?"),
        "tls": d.get("tls", {}).get("version", "none"),
    }

with concurrent.futures.ThreadPoolExecutor(max_workers=8) as pool:
    rows = list(pool.map(check, DOMAINS))

rows.sort(key=lambda r: r["days"])
print(f"{'Domain':35s} {'Days':>5s} {'TLS':>8s}  Issuer")
for r in rows:
    flag = "EXPIRED" if r["expired"] else str(r["days"])
    print(f"{r['domain']:35s} {flag:>5s} {r['tls']:>8s}  {r['issuer']}")

Eight workers against a 500-domain list completes in roughly two minutes. At the Ultra tier (10,000 requests for $29/month), you can run that same sweep daily for the entire month and still have headroom for other endpoints.

Pricing and Rate Limits vs Standalone SSL Monitors

Plan Requests/mo Price Daily SSL Checks On
Basic (Free) 100 $0 ~3 domains
Pro 1,000 $9 ~33 domains
Ultra 10,000 $29 ~333 domains
Mega 50,000 $79 ~1,666 domains

Standalone SSL monitors (KeyChest, SSLMate Cert Spotter, Updown.io) give you dashboards and built-in alerting out of the box. The DetectZeStack approach trades dashboards for API flexibility: you write the alerting in your own toolchain, and you get tech detection, DNS, security headers, and CPE-based vulnerability data on the same key. For teams that already run their own monitoring (Datadog, Grafana, PagerDuty, n8n, Zapier), API-first is usually less work in the long run.

Get Your API Key and Start Monitoring

The free tier covers daily SSL checks on three domains with no credit card. The Pro tier at $9/month covers 33 domains daily, which is enough for most early-stage SaaS deployments. Sign up on RapidAPI, paste the key into the curl example above, and you have a working SSL monitoring pipeline in under five minutes.

Conclusion

Certificate monitoring is a solved problem; the only question is whether you have wired up the solution. An SSL monitoring API gives you structured data over a single HTTP request, which means you can build the alerting that fits your team rather than adapting to someone else's dashboard. The DetectZeStack /certificate/check endpoint returns expiry, issuer, chain, SANs, key algorithm, and TLS version in one JSON response, and the same API key handles tech stack detection, DNS, and security headers on the same quota. That combination is what makes "monitor every cert across the org" something you actually finish, not something on a quarterly roadmap.

Related Reading

Start Monitoring SSL Certificates Today

Free tier: 100 requests/month, no credit card. Structured JSON for expiry, chain, SANs, and TLS version on every check.

Get your free API key

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.