Back to blog
FILE 0x9D·ONE CURL COMMAND TO CHECK ANY CERT AND DOMAIN — CERTWATCH'S

One curl command to check any cert and domain — CertWatch's public API

June 10, 2026 · certwatch, tls, ssl, api, devops, monitoring

The most common thing engineers want before signing up for any monitoring product is to verify it works on their domain. CertWatch has a public endpoint for exactly this:

curl -s "https://certwatch.app/check/public?domain=example.com" | python3 -m json.tool

Response:

{
  "domain": "example.com",
  "resolves": true,
  "cert_expires_at": "2026-09-14",
  "cert_days_left": 96,
  "cert_chain_ok": true,
  "checked_at": "2026-06-10T06:00:00Z"
}

That's the SSL certificate expiry, the chain validation result (full trust chain to a known root, no self-signed intermediates), and DNS resolution — all in one call. Rate-limited to 3 requests/minute per IP. No API key, no account.

What the paid tier adds

The public endpoint intentionally omits domain expiry (WHOIS registrar-expiration-date). That's behind the API key:

curl -s "https://certwatch.app/check?domain=example.com" \
  -H "X-Api-Key: your-api-key"

Response adds:

{
  "domain_expires_at": "2027-01-22",
  "domain_days_left": 226,
  "registrar": "NameCheap, Inc."
}

This is the distinction: if you just need to know whether a cert is about to expire (the common case), the public endpoint is free. If you're also monitoring domain renewals — and the cert expiring because someone forgot to renew the domain is a very real failure mode — that's paid.

Webhooks

The paid tier also fires webhooks when anything crosses a threshold. The payload is the same JSON structure as the API response. You can point it at Slack, PagerDuty, a Lambda function, or a custom endpoint:

# Register a webhook
curl -s -X POST "https://certwatch.app/webhooks" \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.slack.com/services/T/B/xxx",
    "domains": ["example.com", "api.example.com"],
    "alert_days": [30, 14, 7, 1]
  }'

The alert_days array controls which thresholds trigger a webhook. Default is [30, 14, 7, 1] — you get a ping at 30 days, two weeks, one week, and the day before. You can tighten it to [7, 1] if you don't want the early warnings.

Bulk CSV import

If you have a list of domains to monitor, you don't have to add them one at a time:

# domains.csv: one domain per line, `domain` header optional
echo -e "domain\nexample.com\napi.example.com\nblog.example.com" | \
  curl -s -X POST "https://certwatch.app/domains/csv" \
    -H "X-Api-Key: your-api-key" \
    --data-binary @-

Response:

{
  "added": 3,
  "skipped_existing": 0,
  "skipped_invalid": 0,
  "skipped_capacity": 0
}

The tier limit is enforced server-side — Starter allows 100 domains, Pro allows 1,000. Import a 50-domain CSV on the Starter tier and all 50 are tracked.

CI pipeline integration

The /check endpoint returns a non-200 when the cert is expired or the chain is broken. That makes it directly usable in CI:

- name: Verify cert before deploy
  run: |
    result=$(curl -sf "https://certwatch.app/check?domain=$DOMAIN" \
      -H "X-Api-Key: $CERTWATCH_API_KEY")
    days_left=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin)['cert_days_left'])")
    if [ "$days_left" -lt 7 ]; then
      echo "::warning::Cert for $DOMAIN expires in $days_left days"
    fi

This pattern works in GitHub Actions, GitLab CI, or any CI system that can run a curl command.

The rate limiting

The public endpoint uses DynamoDB with TTL for rate limiting. Each IP gets 3 requests per 60-second window. The rate limit row expires 90 seconds after creation — a modest over-shoot that prevents edge cases at the window boundary.

The paid endpoint has no rate limit, just the API key auth. Keys are stored as SHA-256 hashes in the database, so a table exfiltration doesn't expose the actual key values.


The public endpoint lives at certwatch.app/check/public. If you're checking certs manually and want automated alerts when they get close to expiry, that's what the product is for.