REST API · v1

TechSpy API

POST a domain and get back its detected tech stack, DNS/DMARC posture, subdomains, and hidden APIs as structured JSON. It's the same engine that powers the app — a single endpoint whose stages you toggle with boolean flags, so one call can be a fast tech-stack read or a full deep audit.

POSThttps://techspy.hi-daniel.com/api/analyze

Quickstart

  1. 1

    Generate a key on the API settings page (Plus or Max plan).

  2. 2

    Send a POST to /api/analyze with your key in the Authorization header.

  3. 3

    Read the JSON — tech_stack is grouped by category, each finding named and versioned.

bash
curl -X POST https://techspy.hi-daniel.com/api/analyze \
  -H "Authorization: Bearer ts_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://stripe.com",
    "static_analysis": true,
    "dns_scan": true,
    "subdomain_analysis": true
  }'

Authentication

Every request is authenticated with a Bearer API key. Keys are prefixed ts_, generated on the API settings page, and available on the Max plan. The key is shown once at creation — store it securely; only a hash is kept on our side.

http
Authorization: Bearer ts_YOUR_API_KEY

Regenerating a key invalidates the old one immediately. If a key leaks, revoke it from the settings page.

POST /api/analyze

There is a single endpoint. Which stages run is controlled entirely by the boolean flags in the body — so one call can be a fast tech-stack read or a full deep audit.

POSThttps://techspy.hi-daniel.com/api/analyze

Parameters

JSON body. Only url is required; every stage flag defaults off except static_analysis.

FieldTypeDefaultDescription
urlstring—Required. The website to analyze, e.g. https://stripe.com.
static_analysisbooleantrueTech-stack detection (HTML + JS-runtime + HTTP headers). On by default.
dns_scanbooleanfalseDNS / DMARC / SPF / DKIM audit, CDN, TLS, email provider.
subdomain_analysisbooleanfalseDiscover subdomains and group them by layer (app, docs, api…).
sitemap_scanbooleanfalseParse sitemap structure and page tree.
deep_scanPaidbooleanfalseHeadless render + HAR capture — surfaces hidden APIs & SDKs. Takes minutes. Consumes 1 Deep Scan credit.
interactPaidbooleanfalseLLM drives the page (click/fill) to reveal post-interaction tools. Implies deep_scan. Consumes 1 Interact credit.
forcebooleanfalseBypass per-stage caches and force a fresh scan.
savebooleanfalseSet true to save an API-key scan to your scan history (dashboard, Zapier's New Saved Scan, MCP) and get saved_scan_id back. The MCP server and CLI save by default.

Response

200 OK with the analysis. Sections beyond tech_stack only appear when their flag was set. Each finding carries a confidence marker; a blocked scan is reported honestly in warnings rather than faked.

json
{
  "url": "https://stripe.com",
  "status": "completed",
  "analyzed_at": "2026-07-07T18:20:04.512Z",
  "tech_stack": {
    "Framework": [{ "name": "Next.js", "version": "14" }],
    "Hosting & CDN": [{ "name": "Cloudflare" }],
    "Analytics": [{ "name": "Segment" }],
    "Payment": [{ "name": "Stripe" }]
  },
  "dns": {
    "cdn": "Cloudflare",
    "dns_provider": "Cloudflare",
    "email_provider": "Google Workspace",
    "tls_issuer": "Let's Encrypt",
    "email_security": { "spf": "pass", "dmarc": "reject" },
    "scorecard": { "grade": "A", "overall": 92, "security": 88 }
  },
  "subdomains": [{ "hostname": "dashboard.stripe.com" }],
  "layers": { "app": { "label": "Application", "subdomains": ["dashboard.stripe.com"] } },
  "api_domains": [],
  "pages_analyzed": ["stripe.com"],
  "warnings": null,

  "static_analysis": true,
  "dns_scan": true,
  "subdomain_analysis": true,
  "deep_scan": false,
  "interact": false
}

Rate limits & tiers

API calls draw on the same allowances as the app. Every response includes an X-RateLimit-Remaining header.

Daily scans

Every call counts against your plan's daily scan cap: Plus 30/day, Max unlimited. Resets 00:00 UTC.

Deep Scan credits

deep_scan spends 1 credit per call. Plus includes 10/mo, Max 50/mo.

Interact credits

interact spends 1 credit per call (and implies deep_scan). Plus includes 5/mo, Max 25/mo.

Over a limit, the API returns 402 with a message — any credits consumed on a rejected call are refunded automatically.

Errors

Errors return a JSON body of the form { "error": "…" } with the status below.

400Missing/invalid url, invalid JSON body, or an SSRF-blocked target.
401Missing or invalid API key on an endpoint that needs one; Deep Scan / Interact always need a key.
402Daily scan limit reached, or Deep Scan / Interact credits exhausted. Check GET /api/account.
403The saved scan belongs to another account.
404Saved scan not found.
429Rate limited: per-IP scan burst limit, strategy-analysis generation above 10 per hour per IP, or a second forced regeneration of the same scan within 24h.
500Scan engine error. Safe to retry.

Account & saved scans

Check your budget before scanning, then read back saved scans and their strategy analysis. None of these use credits.

GET /api/accountPlan, today's scans used / remaining, and Deep Scan / Interact credits left.
GET /api/scans/list?limit=&offset=Your saved scans, newest first (paginated).
GET /api/scans/{id}One saved scan with its full result.
GET /api/scans/{id}/analysisThe five-pillar strategy analysis, if one exists.
POST /api/scans/{id}/analysisGenerate it (free; cached). body { "force": true } regenerates: your own scans only, once per scan per 24h. Max 10 generations per hour per IP. Takes a few minutes; returns 202 { status: "generating" } if one is already running.
bash
curl https://techspy.hi-daniel.com/api/account \
  -H "Authorization: Bearer ts_YOUR_API_KEY"
json
{
  "email": "you@company.com",
  "tier": "plus",
  "api_access": true,
  "daily_scans": { "limit": 30, "used": 4, "remaining": 26, "resets_at": "2026-10-01T00:00:00.000Z" },
  "credits": { "deep_scan": 9, "interact": 5 }
}

null limit / remaining means unlimited (Max).

Automation endpoints

Beyond the scan endpoint, these power the Zapier triggers and let you pull report feeds, sync saved scans, and manage domain monitoring directly with your API key.

Automation & Monitoring (/api/zapier/*)

These endpoints back the Zapier integration, but you can call them directly with a Bearer ts_ key. Use them to pull report feeds, look up your saved scans, manage domain watches, and read detected changes. Base URL: https://techspy.hi-daniel.com. Every endpoint requires auth, scopes to your own data, and returns newest-first arrays. Each item includes a stable id for deduping.

GET /api/zapier/reports

  • Returns the newest published reports across all content types. Use it to post new reports to Slack or a newsletter as they go live.
  • Auth: Bearer ts_ API key
  • Returns: array of { id, title, content_type, slug, url, published_at }
curl https://techspy.hi-daniel.com/api/zapier/reports \
  -H "Authorization: Bearer ts_YOUR_API_KEY"

GET /api/zapier/scans

  • Returns your recent saved scans with tech and DNS summaries. Use it to sync scan results into a sheet or CRM.
  • Auth: Bearer ts_ API key
  • Returns: array of { id, url, created_at, tech_count, tech_summary, dns_grade }
curl https://techspy.hi-daniel.com/api/zapier/scans \
  -H "Authorization: Bearer ts_YOUR_API_KEY"

GET /api/zapier/watches

  • Returns the domains you are watching for changes.
  • Auth: Bearer ts_ API key
  • Returns: array of { id, url, created_at, last_checked_at }
curl https://techspy.hi-daniel.com/api/zapier/watches \
  -H "Authorization: Bearer ts_YOUR_API_KEY"

POST /api/zapier/watches

  • Adds a domain to your watch list. This is an upsert: calling it again with the same URL returns the existing watch instead of creating a duplicate.
  • Auth: Bearer ts_ API key
  • Body params:
Param Type Default Description
url string — Domain URL to watch
  • Returns: { id, url, created_at, watching } where watching is always true
curl -X POST https://techspy.hi-daniel.com/api/zapier/watches \
  -H "Authorization: Bearer ts_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://stripe.com"}'

DELETE /api/zapier/watches

  • Removes a watch you own. Pass the watch id returned by the GET or POST calls above.
  • Auth: Bearer ts_ API key
  • Query params:
Param Type Default Description
id string — ID of the watch to remove
  • Returns: { ok } where ok is true
curl -X DELETE "https://techspy.hi-daniel.com/api/zapier/watches?id=wch_1a2b3c" \
  -H "Authorization: Bearer ts_YOUR_API_KEY"

GET /api/zapier/changes

  • Returns recent changes detected for your account, filtered by type. Use it to trigger an alert when a domain adds a tech, exposes a new subdomain, or changes an email record. Which fields are populated depends on type: tech and subdomain changes use item (and may include items); email changes use field, old_value, and new_value.
  • Auth: Bearer ts_ API key
  • Query params:
Param Type Default Description
type string — Change type: tech, subdomain, or email
  • Returns: array of { id, url, change_type, detected_at, item, items, field, old_value, new_value }. Present fields depend on type — tech/subdomain populate item/items; email populates field, old_value, new_value.
curl "https://techspy.hi-daniel.com/api/zapier/changes?type=tech" \
  -H "Authorization: Bearer ts_YOUR_API_KEY"

MCP for AI agents

TechSpy runs as a remote MCP server so Claude Code, Cursor and other agents can scan sites and read results as native tools. It uses Streamable HTTP at https://techspy.hi-daniel.com/api/mcp and your API key — same daily scans and credits as the REST API. See what agents can do with it.

Claude Code

bash
claude mcp add --transport http techspy https://techspy.hi-daniel.com/api/mcp \
  --header "Authorization: Bearer ts_YOUR_API_KEY"

Cursor (~/.cursor/mcp.json)

json
{
  "mcpServers": {
    "techspy": {
      "url": "https://techspy.hi-daniel.com/api/mcp",
      "headers": { "Authorization": "Bearer ts_YOUR_API_KEY" }
    }
  }
}

Any client that supports remote Streamable HTTP servers with a custom header works the same way. The key is also accepted without the Bearer prefix or as an x-api-key header.

scan_domainDetect a site's tech stack; optional dns, subdomains, sitemap, deep, interact. Uses 1 daily scan (+ credits for deep / interact) and returns a saved_scan_id.
get_accountPlan, scans left today and remaining credits. Free.
list_scansYour saved scans, newest first. Free.
get_scanTech stack, DNS grade, subdomains and sitemap summary of a saved scan. Free.
get_strategy_analysisFive-pillar strategy analysis of a saved scan; generate: true creates one. No credits.

Out of scans or credits, a tool returns the API's 402 message unchanged so the agent can tell you why.

Command-line (CLI)

The techspy CLI wraps the same API for terminals, scripts and coding agents. Node 18+, no install needed with npx.

bash
export TECHSPY_API_KEY=ts_YOUR_API_KEY     # or: npx techspy login

npx techspy scan stripe.com
npx techspy scan stripe.com --dns --subdomains --json
npx techspy account
npx techspy scans list
npx techspy analysis <scan-id> --generate

--json prints machine-readable output, and exit codes tell agents what happened without parsing text: 3 invalid key, 4 out of scans or credits (402), 5 rate limited, 6 not found.

Use with Zapier (no app required)

You don't need a published Zapier integration to automate TechSpy. Add a Webhooks by Zapier → Custom Request action and point it at the endpoint with your key:

text
Method:  POST
URL:     https://techspy.hi-daniel.com/api/analyze
Headers: Authorization | Bearer ts_YOUR_API_KEY
         Content-Type  | application/json
Data:    { "url": "{{trigger.domain}}", "dns_scan": true }

Map any field from an earlier Zap step into url, and use the returned JSON in later steps.

Prefer the native integration? The TechSpy for Zapier guide covers all 5 triggers and 9 actions, including domain-change monitoring.

Ready to build?

Generate a key and make your first call in under a minute.