API Documentation
Complete reference for all network diagnostic endpoints · OpenAPI 3.1 · interactive playground
Jump to Section
📖 Jump to Section
https://your-worker.your-subdomain.workers.dev
All endpoints return JSON: { status, message, data } · errors: { status: "error", code, message, data }
IP Address Intelligence
Multi-provider lookup (ip-api.com → ipwho.is → ipinfo.io) with failover, 24h cache, reverse DNS, threat flags, and meta (provider, cached, elapsedMs). Omitting data returns the caller's IP. SSRF-guarded.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| data | string | optional | IPv4, IPv6, or domain. Default: caller IP. |
Cache: public, max-age=300, s-maxage=3600
DNS Lookup — Multi-Resolvers
Queries Cloudflare, Google, and Quad9 over DNS-over-HTTPS. Returns per-resolver answers, DNSSEC status (validated/secure/bogus/none), cross-resolver diff, homograph/punycode flags.
Cache: public, max-age=60, s-maxage=600
HTTP Header Checker
HEAD request with redirect-chain tracking (max 5 hops, each hop validated), HTTP version, full headers, and a 0-100 security score with per-header checks.
Port Scanner — Streaming
Concurrent engine (32 workers, randomized timeout jitter, banner capture). Range syntax 80,443,8000-8010, max 50 ports.
SSE: ?stream=1 emits start, progress, result, done events with 15s heartbeats.
Status: /api/portscan?scanId={id} returns snapshot; scans expire after 10 minutes.
SSL/TLS Audit
Chain walk with per-level verification, OCSP revocation check (AIA responder), TLS version matrix (1.0-1.3), cipher negotiation probe, and 0-100 security score with breakdown + letter grade.
Allowed ports: 80, 443, 465, 993, 995, 8443
WHOIS / RDAP Lookup
RDAP-first with IANA bootstrap (cached 24h), fallback to raw port-43 WHOIS at whois.iana.org. Normalized fields: registrar, dates, nameservers, status codes, abuse contact, DNSSEC flag. Supports domains, IP ranges (inetnum), and AS{number}.
Cache: public, max-age=3600, s-maxage=86400
Certificate Transparency
Subdomain discovery from crt.sh with certspotter fallback. Deduplicated names, wildcard badges, issuer lists, first/last seen, and an issuance timeline. Cached 24h (crt.sh is slow).
Batch Scan Engine
Create an async job. Body: { tool: "dns"|"ip"|"ssl", items: ["a.com","8.8.8.8",...], webhookUrl?, webhookSecret? }. Max 200 unique items, concurrency 5, per-item pacing, automatic retry (2x), TTL 15 min.
Job snapshot: status (created/queued/running/partial/done/failed/aborted), progress, ETA, results.
SSE events: start, progress, item, done.
Abort a running job.
AI Diagnostic Report
Generates a human-language diagnostic summary via an OpenAI-compatible provider. Requires AI_API_KEY env. Results cached 24h (zero re-bill), daily budget guardrail (BUDGET_DAILY_USD), circuit breaker on repeated failures.
SSE: ?stream=1 streams data: {"token": "..."} chunks.
Health & Metrics
Memory, uptime, upstream reachability (rdap.org, Cloudflare DoH, crt.sh). Returns 503 when degraded. Exempt from rate limits.
Rate-limit stats, cache hit ratios, error counts, active scans/jobs, KV mode. Exempt from rate limits.
Interactive Playground
Try any endpoint live. Response is validated against the OpenAPI contract in development mode.
"Press Run to fetch"
Error Codes
| Code | HTTP | Meaning | Example body |
|---|---|---|---|
| BAD_REQUEST | 400 | Missing/invalid parameter | {"status":"error","code":"BAD_REQUEST","message":"...","data":null} |
| INVALID_TARGET | 400 | Malformed hostname/IP/URL | {"code":"INVALID_TARGET",...} |
| BLOCKED_TARGET | 403 | SSRF: private/loopback/link-local/metadata target | {"code":"BLOCKED_TARGET","message":"resolves to blocked address 169.254.169.254 (...)"} |
| REBINDING_DETECTED | 403 | DNS answers changed between lookups | {"code":"REBINDING_DETECTED",...} |
| NOT_FOUND | 404 | No data (domain/scan/share) | {"code":"NOT_FOUND","message":"Share link not found or expired"} |
| RATE_LIMITED | 429 | Too many requests; Retry-After header set | {"code":"RATE_LIMITED","data":{"retryAfter":42,...}} |
| BUDGET_EXHAUSTED | 402 | Daily AI budget spent | {"code":"BUDGET_EXHAUSTED",...} |
| UPSTREAM_ERROR | 502 | Upstream provider failed (after failover) | {"code":"UPSTREAM_ERROR",...} |
| SERVICE_UNAVAILABLE | 503 | Degraded (health) | {"code":"SERVICE_UNAVAILABLE",...} |
| INTERNAL_ERROR | 500 | Unexpected crash | {"code":"INTERNAL_ERROR","message":"Internal server error"} |
Webhooks (HMAC-Signed)
Pass webhookUrl + webhookSecret when creating a batch job. On completion the engine POSTs:
POST {webhookUrl}
Headers:
X-Webhook-Signature: sha256={hex HMAC-SHA256 of raw body using webhookSecret}
X-Webhook-Event: scan.completed
X-Webhook-Idempotency-Key: {jobId}:{attempt}
Body: { "event":"scan.completed", "scanId":"...", "tool":"dns",
"status":"done", "timestamp":"...", "attempt":1,
"summary":{ "total":150, "ok":148, "failed":2 },
"results":[ {item,status,result} ] }
Retries: 3 attempts with 1s/5s/30s backoff, 10s timeout. Verify the signature server-side with your secret — never trust an unauthenticated webhook.
Rate Limits
| Endpoint | Limit | Burst |
|---|---|---|
| /api/ip | 30/min/IP | 5 |
| /api/dns | 60/min/IP | 10 |
| /api/headers | 30/min/IP | 5 |
| /api/portscan | 10/min/IP | 2 |
| /api/ssl | 30/min/IP | 5 |
| /api/whois | 20/min/IP | 4 |
| /api/ct | 10/min/IP | 2 |
| /api/scan (create) | 5/min/IP | 2 |
| /api/ai | 5/min/IP | 1 |
| /api/share, /api/health, /api/metrics | exempt / 30 | 10 |
Sliding window (60s) + token bucket. Headers: X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After. Client IP taken from the first x-forwarded-for value. Optional Upstash Redis backend via UPSTASH_REDIS_REST_URL.