API Reference
The MadeWithTech API lets you scan websites and retrieve tech stack results programmatically. All endpoints are RESTful and return JSON.
https://madewith.tech/api/v1Pro 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_hereAPI keys start with sk_ and are shown once on creation. Store them securely.
Scan a website
/api/v1/scanScan 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
| Field | Type | Description |
|---|---|---|
url required | string | Full URL to scan (https://...) |
private | boolean | Hide 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
/api/v1/results/:domainRetrieve 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
| Status | Meaning |
|---|---|
| 400 | Bad request — missing or invalid url field |
| 401 | Unauthorized — missing or invalid API key |
| 403 | Forbidden — Pro subscription required |
| 404 | Not found — no public scan for this domain |
| 429 | Too many requests — rate limit exceeded |
| 500 | Internal server error — scan failed |
Rate limits
| Endpoint | Limit | Window |
|---|---|---|
| POST /api/v1/scan | 1,000 requests | per hour per API key |
| GET /api/v1/results/* | 1,000 requests | per 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();