API Reference

The MadeWithTech API lets you scan websites and retrieve tech stack results programmatically. All endpoints are RESTful and return JSON.

Base URLhttps://madewith.tech/api/v1

Pro required. API access requires an active Pro subscription. Upgrade at /pricing →

Authentication

All API requests require a Bearer token in the Authorization header. Generate API keys from your dashboard settings.

Authorization: Bearer sk_your_api_key_here

API keys start with sk_ and are shown once on creation. Store them securely.

Scan a website

POST/api/v1/scan

Scan a URL and detect its full technology stack. This opens the URL in a headless browser, runs detection scripts, and optionally uses AI for deeper analysis.

Request body

FieldTypeDescription
url requiredstringFull URL to scan (https://...)
privatebooleanHide from public feed (default: false)
{
  "url": "https://example.com",
  "private": false
}

Response

{
  "scanId": "abc123",
  "siteId": "def456",
  "url": "https://example.com",
  "status": "completed",
  "detectedTechs": [
    {
      "tech": "next.js",
      "displayName": "Next.js",
      "version": "14.2.0",
      "category": "framework",
      "confidence": "high",
      "source": "script"
    },
    {
      "tech": "react",
      "displayName": "React",
      "version": "18.2.0",
      "category": "framework",
      "confidence": "high",
      "source": "both"
    },
    {
      "tech": "node.js",
      "displayName": "Node.js",
      "version": null,
      "category": "language",
      "confidence": "high",
      "source": "ai"
    }
  ],
  "aiUsed": true,
  "scriptsRun": 42,
  "durationMs": 3241
}

Get latest scan results

GET/api/v1/results/:domain

Retrieve the most recent public scan result for a domain. Returns 404 if no public scan exists.

GET /api/v1/results/vercel.com
Authorization: Bearer sk_...

Response

{
  "domain": "vercel.com",
  "url": "https://vercel.com",
  "scanId": "abc123",
  "scanDate": "2026-05-18T12:00:00.000Z",
  "detectedTechs": [...],
  "scriptsRun": 42,
  "aiUsed": true,
  "durationMs": 2891
}

Error codes

StatusMeaning
400Bad request — missing or invalid url field
401Unauthorized — missing or invalid API key
403Forbidden — Pro subscription required
404Not found — no public scan for this domain
429Too many requests — rate limit exceeded
500Internal server error — scan failed

Rate limits

EndpointLimitWindow
POST /api/v1/scan1,000 requestsper hour per API key
GET /api/v1/results/*1,000 requestsper hour per API key

Rate limit headers are included in every response: X-RateLimit-Remaining, X-RateLimit-Reset.

Code examples

curl

curl -X POST https://madewith.tech/api/v1/scan \
  -H "Authorization: Bearer sk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

JavaScript (fetch)

const response = await fetch('https://madewith.tech/api/v1/scan', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_your_api_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ url: 'https://example.com', private: false }),
});

const data = await response.json();
console.log(data.detectedTechs);
// [{ tech: 'next.js', displayName: 'Next.js', version: '14.2.0', ... }, ...]

Python

import requests

response = requests.post(
    'https://madewith.tech/api/v1/scan',
    headers={
        'Authorization': 'Bearer sk_your_api_key',
        'Content-Type': 'application/json',
    },
    json={'url': 'https://example.com', 'private': False}
)

data = response.json()
for tech in data['detectedTechs']:
    print(f"{tech['displayName']} {tech['version'] or ''} ({tech['confidence']})")

Get results for a domain

const response = await fetch(
  'https://madewith.tech/api/v1/results/stripe.com',
  {
    headers: { 'Authorization': 'Bearer sk_your_api_key' }
  }
);

const { detectedTechs, scanDate } = await response.json();