Skip to Content

Tech Stack

REST endpoints for Tech Stack. Base URL https://api.competlab.com; every request needs a CL-API-Key header (see Authentication). Responses wrap in { item } or { items }; errors in { error }.

Start an async tech-stack scan

POST/v1/tools/tech-stack/scans

Start an asynchronous tech-stack detection scan for a public domain. Detects the frontend frameworks, hosting and CDN infrastructure, CMS, analytics and growth tools, and customer engagement services in use. Returns sub-second with item: { id, status: "queued", createdAt, expiresAt } — poll GET /v1/tools/tech-stack/scans/{scanId} until status is completed or failed. Most scans complete in seconds; heavy-render sites can take up to ~90 seconds. Result and error payloads are persisted for 24h, after which the scan auto-deletes and GET returns 404. No project required. Suitable for ad-hoc competitive lookups, integration into onboarding flows, and pre-sales discovery — and the only supported shape for MCP clients (Cursor / Claude Desktop hardcode 60-second tool-call timeouts).

Returns · { item }

Request bodyapplication/json

FieldTypeDescription
domainstringTarget domain to fingerprint. Accepts a bare hostname or a full URL — normalized (lowercased, scheme and path stripped) before scanning.

Request

curl -X POST "https://api.competlab.com/v1/tools/tech-stack/scans" \ -H "CL-API-Key: YOUR_COMPETLAB_API_KEY" \ -H "Content-Type: application/json" \ -d '{"domain":"stripe.com"}'

Response 200 OK

{ "item": { "id": "6638e9a1b2c3d4e5f6a7b8c9", "status": "queued", "createdAt": "2026-05-17T14:30:00.000Z", "expiresAt": "2026-05-18T14:30:00.000Z" } }

Errors

StatusCodeMeaning
400invalid_parametersBad request — the payload failed validation.
401api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scopeThe CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope.
429rate_limit_exceededRate limit exceeded — retry with backoff.
502bad_gatewayUpstream fetch failed (e.g. the target page could not be retrieved).

Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.

{ "error": { "code": "invalid_parameters", "message": "Domain is required", "status": 400 } }

Transient failures (429, 5xx) are safe to retry with exponential backoff.

Get an async tech-stack scan by ID

GET/v1/tools/tech-stack/scans/{scanId}

Get the current state of an async tech-stack scan. Returns the scan’s lifecycle (queued / running / completed / failed) along with createdAt and expiresAt always, plus startedAt once the runner picks it up and completedAt once it reaches a terminal state. On completed the full canonical scan response is in item.result (categorized technology hits with evidence). On failed the failure details are in item.error with a machine-readable code — currently homepage_fetch_failed (upstream homepage fetch threw) or scan_failed (any other error during scan execution). Scoped to the API key’s organization — cross-tenant access, never-existed IDs, expired IDs (24h TTL), and malformed IDs all return 404 scan_not_found with an identical envelope to prevent existence-disclosure. Typically sub-second — safe to poll on a 2–5 second interval depending on your timeout budget.

Returns · { item }

Path parameters

NameTypeDescription
scanIdstring

Request

curl "https://api.competlab.com/v1/tools/tech-stack/scans/65a1b2c3d4e5f6a7b8c9d0e1" \ -H "CL-API-Key: YOUR_COMPETLAB_API_KEY"

Response 200 OK

{ "item": { "id": "6638e9a1b2c3d4e5f6a7b8c9", "status": "completed", "createdAt": "2026-05-17T14:30:00.000Z", "expiresAt": "2026-05-18T14:30:00.000Z", "startedAt": "2026-05-17T14:30:00.412Z", "completedAt": "2026-05-17T14:30:45.218Z", "result": { "domain": "stripe.com", "finalUrl": "https://stripe.com/", "fetchedAt": "2026-05-17T14:30:45.000Z", "totalTechnologies": 3, "techStack": [ { "name": "Next.js", "evidenceCount": 2, "evidence": [ { "kind": "html", "source": "/_next/static/", "matched": "<script src=\"/_next/static/chunks/main-app-abc123.js\"" }, { "kind": "header", "source": "x-powered-by", "matched": "Next.js" } ] }, { "name": "Cloudflare", "evidenceCount": 1, "evidence": [ { "kind": "header", "source": "server", "matched": "cloudflare" } ] } ], "growthStack": [ { "name": "HubSpot", "evidenceCount": 1, "evidence": [ { "kind": "html", "source": "js.hs-scripts.com", "matched": "<script src=\"//js.hs-scripts.com/1234567.js\"" } ] } ], "engagementStack": [] } } }

Errors

StatusCodeMeaning
401api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scopeThe CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope.
404scan_not_foundNo scan matches the id in the path.
429rate_limit_exceededRate limit exceeded — retry with backoff.

Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.

{ "error": { "code": "api_key_invalid", "message": "Invalid API key", "status": 401 } }

Transient failures (429, 5xx) are safe to retry with exponential backoff.

Last updated on