API Documentation
Query a public URL and receive technology detections, metadata, confidence levels, evidence, safe enrichment probes, scan limits, and typed error codes. HEAD returns the same status and headers without a body; OPTIONS lists supported methods. Successful reports can be cached for 60 seconds and retain their original analyzedAt timestamp.
Analyze endpoint
Analyze a public website. Host-only inputs are normalized to HTTPS, with an HTTP fallback when HTTPS was inferred.
Query parameters
urlPublic URL or host to analyze. Example: https://example.com
Example request
curl "https://stack.leunos.com/api/analyze?url=https://example.com"Response format
Responses include stable slugs, rule IDs, confidence breakdowns, structured signals, summary totals, scan limits, bounded DNS/resource probes, and warnings.
Example response
{
"requestedUrl": "https://example.com",
"url": "https://example.com/",
"title": "Example Domain",
"meta": {
"responseTime": 182,
"statusCode": 200,
"redirected": false,
"contentType": "text/html; charset=UTF-8",
"htmlBytes": 1653,
"hostname": "example.com"
},
"technologies": [
{
"name": "Cloudflare",
"slug": "cloudflare",
"category": "CDN",
"icon": "Cloud",
"confidence": "high",
"confidenceScore": 90,
"ruleIds": ["cdn.cloudflare"],
"confidenceBreakdown": {
"header": 90,
"dns": 90
},
"evidence": ["header cf-ray: 8a12..."],
"signals": [
{
"source": "header",
"label": "header cf-ray",
"value": "8a12..."
}
]
}
],
"summary": {
"total": 1,
"categories": { "CDN": 1 },
"confidence": { "high": 1, "medium": 0, "low": 0 }
},
"scan": {
"durationMs": 182,
"rulesVersion": "2026.09.15",
"limits": {
"totalTimeoutMs": 30000,
"requestTimeoutMs": 10000,
"dnsTimeoutMs": 1500,
"maxHtmlBytes": 2097152,
"maxRedirects": 4,
"maxProbeRequests": 6,
"maxProbeRedirects": 1,
"maxConcurrentProbes": 2,
"maxProbeBytes": 262144,
"maxTotalProbeBytes": 1048576,
"probeTimeoutMs": 3000,
"maxDnsRecords": 12,
"maxDnsResponseBytes": 65536,
"maxSubrequests": 40,
"maxInputUrlChars": 4096,
"maxResourceUrlChars": 4096,
"maxDiscoveredAssets": 256,
"maxTitleChars": 300,
"maxDescriptionChars": 1024,
"maxGeneratorChars": 256,
"maxLanguageChars": 64,
"maxApiBodyBytes": 8192
},
"warnings": [],
"probes": [
{
"type": "dns",
"target": "A example.com",
"status": "ok",
"durationMs": 18
}
]
}
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_URL | Missing URL, malformed URL, unsupported scheme, or embedded credentials. |
| 405 | METHOD_NOT_ALLOWED | Use GET or HEAD; OPTIONS describes the supported methods. |
| 400 | BLOCKED_TARGET | Localhost, private/reserved IPs, internal suffixes, or unsafe DNS answers. |
| 502 | TOO_MANY_REDIRECTS | The upstream site exceeded the redirect limit. |
| 502 | UPSTREAM_UNREACHABLE | The upstream site could not be reached or returned invalid redirect behavior. |
| 502 | UNSUPPORTED_CONTENT | The upstream response was not HTML, XML, or text. |
| 503 | SCAN_LIMIT_REACHED | The analyzer exhausted its outbound request budget. |
| 504 | UPSTREAM_TIMEOUT | The upstream site timed out, or the total scan deadline was reached. |
| 500 | INTERNAL_ERROR | An unexpected analyzer failure. The response never includes a stack trace. |
Safety limits
Notes
The analyzer is stateless and heuristic. It blocks known unsafe URL forms, validates redirects, checks public DNS answers before fetching, and only enriches from discovered manifests/assets with strict limits. Oversized primary HTML is truncated and analysis continues with a CONTENT_TRUNCATED warning; oversized probes are skipped rather than failing the scan. Production deployments should still pair it with Cloudflare-level rate limiting and abuse controls.