Public API · Free · No signup

Build with the Decryption Blast Radius API

The same API that powers npx pqcheck, the browser extension, and the GitHub Action. Free, no signup, no API key. Default 600 requests/hour per IP; 2000/hour for our own first-party UAs (pqcheck-cli, cipherwake-mcp, pqcheck-action, cipherwake-extension) so AI-coder workflows on shared-IP hosts don't hit the wall.

30-second quickstart

Scan any HTTPS domain — returns a complete JSON report with score, grade, findings, and component breakdown. Try it from your terminal:

# Quick scan
curl -s "https://www.cipherwake.io/api/scan?domain=stripe.com" | jq '.grade, .score'

# Or use the CLI wrapper (also free, also no signup)
npx pqcheck stripe.com

Both call the same endpoint. Pick whichever fits your workflow.

Endpoint reference

All endpoints live under https://www.cipherwake.io. Responses are JSON unless noted. CORS-enabled (Access-Control-Allow-Origin: *) so you can call directly from browser code.

EndpointMethodPurposeReturns
/api/scan?domain=<d> free GET Full Decryption Blast Radius scan JSON — score, grade, findings, components, public surface details
/api/history?domain=<d>&days=N free GET Score history (default 90 days) JSON — array of {score, grade, recordedAt}
/api/badge?domain=<d> free GET Embeddable SVG badge SVG image
/api/r?domain=<d> free GET Full HTML report (shareable URL) HTML
/api/og?domain=<d> free GET Social-media OG image (Twitter/Slack/LinkedIn unfurl) PNG
/api/feed.xml free GET RSS/Atom feed (recent scans, watchlists, methodology updates) RSS XML
/api/sitemap.xml free GET SEO sitemap XML

Anatomy of /api/scan

The main endpoint. Pass a domain, get a complete report.

Request

GET /api/scan?domain=stripe.com&source=my-tool

Optional query params:
  domain      required — public HTTPS domain (apex; we strip leading "www.")
  source      optional — for analytics attribution. Examples: ext, my-tool
  force       optional — pass "1" to bypass our 5-min server-side cache (debug)

Response (abbreviated)

{
  "domain": "stripe.com",
  "score": 5.5,
  "grade": "C",
  "scoreLabel": "MEDIUM",
  "reachable": true,
  "impact": {
    "headline": "If quantum decryption arrives in 2030-2040, harvested traffic...",
    "topContributors": [...]
  },
  "findings": [
    { "title": "RSA fallback enabled", "severity": "high", "detail": "..." },
    { "title": "HSTS preload increases key persistence", "severity": "medium", "detail": "..." }
  ],
  "components": {
    "keyExchange":   { "raw": 7, "weight": 0.35, "contribution": 2.45, "rationale": "..." },
    "certLifetime":  { "raw": 5, "weight": 0.25, "contribution": 1.25, "rationale": "..." },
    "keyPersistence":{ "raw": 7, "weight": 0.15, "contribution": 1.05, "rationale": "..." },
    "subdomainScale":{ "raw": 3, "weight": 0.25, "contribution": 0.75, "rationale": "..." }
  },
  "publicSurface": {
    "tlsVersion": "TLSv1.3",
    "hybridPQC": false,
    "daysUntilCertExpiry": 54,
    "wildcardCert": false,
    /* ... full TLS + cert + headers + email-security details ... */
  }
}

See methodology for what each component measures and how the score is computed. The full response is documented in /methodology/decryption-blast-radius.

Code examples

Same call in your stack of choice:

# Just the grade
curl -s "https://www.cipherwake.io/api/scan?domain=stripe.com" | jq -r '.grade'

# Score + top finding titles, formatted
curl -s "https://www.cipherwake.io/api/scan?domain=stripe.com" \
  | jq '{ grade, score, top: .findings[0:3] | map(.title) }'

# Fail a CI step if score >= 7
SCORE=$(curl -s "https://www.cipherwake.io/api/scan?domain=$DOMAIN" | jq -r '.score')
awk -v s="$SCORE" 'BEGIN { exit !(s+0 >= 7) }' && exit 1
// Node 18+ (built-in fetch)
const resp = await fetch(`https://www.cipherwake.io/api/scan?domain=stripe.com`);
const report = await resp.json();
console.log(`${report.domain}: grade ${report.grade}, score ${report.score}`);
report.findings.forEach(f => console.log(`  [${f.severity}] ${f.title}`));
# Python 3.7+ (requests)
import requests
r = requests.get("https://www.cipherwake.io/api/scan", params={"domain": "stripe.com"})
report = r.json()
print(f"{report['domain']}: {report['grade']} ({report['score']}/10)")
for f in report["findings"][:5]:
    print(f"  [{f['severity']}] {f['title']}")
// Go 1.18+
resp, _ := http.Get("https://www.cipherwake.io/api/scan?domain=stripe.com")
defer resp.Body.Close()
var report struct {
    Domain string  `json:"domain"`
    Grade  string  `json:"grade"`
    Score  float64 `json:"score"`
}
json.NewDecoder(resp.Body).Decode(&report)
fmt.Printf("%s: %s (%.1f/10)\n", report.Domain, report.Grade, report.Score)
# Pre-built wrapper around the same API. Zero install.
npx pqcheck stripe.com                         # pretty terminal output
npx pqcheck stripe.com --format json           # raw JSON
npx pqcheck stripe.com --threshold 7           # exit 2 if score >= 7
npx pqcheck stripe.com --format sarif          # SARIF for GitHub Code Scanning
npx pqcheck deps stripe.com --lock             # scan all third-party dependencies
npx pqcheck history stripe.com                 # 90-day score history
npx pqcheck diff old.lock new.lock             # diff QXM lockfiles for regressions

# Source on npm: https://www.npmjs.com/package/pqcheck

Rate limits

Need higher limits, SLA, signed responses, or webhooks? A paid API tier is on the roadmap (Tier 3, see pricing) — sold as SLA + priority queue + signed responses + webhooks, not as "pay because you hit your quota." We're prioritizing it based on real demand: if you'd use it, tell us via the feedback form so we know to build it sooner. Enterprise use cases: email us.

Versioning + stability

Authentication + privacy

API key security

API keys (CIPHERWAKE_API_KEY=qpk_<hex>) authenticate paid-tier usage and bind it to your account's monthly quota. Treat them like passwords.

If a key was exposed publicly (e.g., committed and pushed), rotate immediately and use the feedback form with the exposure window. We can audit usage to see whether the key was abused before you rotated.

Webhook security

Alert webhooks deliver a signed JSON POST to a URL you configure in /account. Every delivery is signed so you can verify the request actually came from Cipherwake before acting on it.

Request shape

POST <your-webhook-url> HTTP/1.1
Host: your-server.example.com
User-Agent: cipherwake-webhook/1.0
Content-Type: application/json
X-Cipherwake-Signature: sha256=<hex-hmac>
X-Cipherwake-Event-Id: <alert-uuid>
X-Cipherwake-Delivery: <attempt-number>

{
  "alertId": "...",
  "domain": "example.com",
  "severity": "high",
  ...
}

Verifying the signature

Each delivery includes an X-Cipherwake-Signature: sha256=<hex> header. The hex value is HMAC-SHA256 of the raw request body using a secret you specify when configuring the webhook. Always verify the signature before acting on the payload — without verification, anyone who guesses your URL could send fake alerts.

Reference verification (Node.js):

import { createHmac, timingSafeEqual } from "node:crypto";

function verifyCipherwakeSignature(rawBody, signatureHeader, secret) {
  if (!signatureHeader?.startsWith("sha256=")) return false;
  const provided = Buffer.from(signatureHeader.slice(7), "hex");
  const expected = createHmac("sha256", secret).update(rawBody).digest();
  if (provided.length !== expected.length) return false;
  return timingSafeEqual(provided, expected);
}

// In your webhook handler — verify on the RAW body before JSON.parse:
const sig = req.headers["x-cipherwake-signature"];
const rawBody = await readRawBody(req); // your framework's raw-body utility
if (!verifyCipherwakeSignature(rawBody, sig, process.env.CIPHERWAKE_WEBHOOK_SECRET)) {
  return res.status(401).json({ error: "invalid signature" });
}
const payload = JSON.parse(rawBody.toString("utf8"));

Replay protection + retry behavior

Choosing a secret

Generate a strong random secret (32+ bytes / 256+ bits) and configure it in /account → Alerts → Webhook URL. Never reuse a secret across multiple integrations. If your secret is exposed (e.g., copy-pasted into a chat), rotate it in /account — old signatures stop verifying immediately.

What this API does NOT do

Pre-built clients

Don't want to call the API directly? We ship four clients that wrap it. All free, all open about what they do.

CLI — npx pqcheck

Zero-install command-line scanner. Same API + nicer output + lockfile / diff / SARIF / cert-analysis subcommands.

Source: github.com/cipherwakelabs/pqcheck · npm: pqcheck · full reference: npx pqcheck --help

Browser extension

Live HNDL grade for every HTTPS site you visit + supply-chain change detection. Color-coded toolbar badge updates per tab; click for the full report.

Install from Chrome Web Store → Firefox AMO + Edge Add-ons coming next.

GitHub Action

Drop into any workflow to gate PRs on quantum-decryption risk regressions.

# .github/workflows/pqcheck.yml
- uses: cipherwakelabs/pqcheck/action@main
  with:
    domain: mycompany.com
    threshold: '7'          # exit 2 if score >= 7
    comment-on-pr: 'true'   # sticky PR comment with summary
    generate-sarif: 'true'  # write SARIF for upload to Code Scanning
    generate-lockfile: 'true' # write cipherwake.lock for diffing

# Optional follow-on step — surface findings in GitHub Security tab
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: pqcheck-results.sarif

Source: github.com/cipherwakelabs/pqcheck/tree/main/action

Built with the API?

If you ship something that uses our API — internal dashboard, Grafana panel, Datadog integration, vendor-risk pipeline, anything — we'd love to know. hello@cipherwake.io.