JobsPipe
API Reference

Stack Scan

Detect a website's technology stack with POST /v1/stack/scan.

POST https://api.jobspipe.dev/v1/stack/scan

Given a domain, returns the technologies it serves - frontend frameworks, analytics, CDNs, payment processors, and SaaS widgets - detected from its live homepage. Results are cached, and a domain's history keeps a new entry only when its stack changes. Requires authentication.

Prefer to explore interactively? The API Explorer has a live playground with the request body, the full response schema, and a "try it" panel.

Request

The body is a JSON object with a single required domain.

FieldTypeDescription
domainstringRequired. The domain to scan, e.g. stripe.com. URLs and a leading www. are normalized off.
modestringOptional. auto (default) tries a fast HTTP fetch, then a headless render if the results are thin.
curl https://api.jobspipe.dev/v1/stack/scan \
  -H "Authorization: Bearer jp_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "stripe.com" }'
import requests

resp = requests.post(
    "https://api.jobspipe.dev/v1/stack/scan",
    headers={"Authorization": "Bearer jp_live_your_key_here"},
    json={"domain": "stripe.com"},
)
resp.raise_for_status()
result = resp.json()
for tech in result["detected"]:
    print(tech["name"], "-", ", ".join(tech["categories"]))
const resp = await fetch("https://api.jobspipe.dev/v1/stack/scan", {
  method: "POST",
  headers: {
    Authorization: "Bearer jp_live_your_key_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ domain: "stripe.com" }),
});
const result = await resp.json();
for (const tech of result.detected) {
  console.log(tech.name, "-", tech.categories.join(", "));
}

Response

A 200 response describes the domain's current stack:

  • detected - an array of detected technologies. Each has name, slug, categories, a confidence score (0-100), an optional version, and metadata such as website, saas, and oss.
  • scanned_at - when this stack snapshot was recorded. A new snapshot is stored only when the detected stack changes, so this is effectively "the stack has been this way since".
  • http_status / render_path - how the domain responded and which fetch path produced the result.
200 OK
{
  "domain": "stripe.com",
  "scanned_at": "2026-06-25T05:56:00Z",
  "http_status": 200,
  "render_path": "curl_cffi",
  "detected": [
    {
      "slug": "react",
      "name": "React",
      "categories": ["JavaScript frameworks"],
      "confidence": 100,
      "version": null,
      "website": "https://react.dev",
      "saas": false,
      "oss": true
    },
    {
      "slug": "cloudflare",
      "name": "Cloudflare",
      "categories": ["CDN"],
      "confidence": 100,
      "version": null,
      "website": "https://www.cloudflare.com",
      "saas": true,
      "oss": false
    }
  ]
}

A reachable domain with no recognizable technologies returns http_status: 200 and an empty detected array. A domain the scanner could not reach returns http_status: 0.

Each call counts as one request against your plan's monthly quota and per-second rate limit. A repeat scan of the same domain within the freshness window is served from cache and still counts as one request. See plans.

Status codes

StatusMeaning
200Success
400Missing or invalid domain
401Missing or invalid API key
402Monthly request quota exceeded
429Per-second rate limit exceeded
502The scanner failed
504The scan timed out

See the error reference for handling guidance.

On this page