API Reference
Run AI-powered website audits programmatically. The Webmatik API gives your tools (Claude Code, Cursor, custom apps) access to the same audit engine that powers webmatik.ai.
Overview
- • Base URL:
https://webmatik.ai/api/v1 - • Authentication: API key in
X-API-Keyheader - • Plans: API access requires Starter, Growth or Agency; API audits count toward the plan's monthly audits (credits are for audits started on the website)
- • Format: JSON request and response, UTF-8
- • Audit time: typically 60-180 seconds end-to-end (background AI vision and GEO continue after the initial response)
Authentication
All requests require an API key. Generate one in your Account settings. Send it in the X-API-Key header.
curl https://webmatik.ai/api/v1/audit \
-H "X-API-Key: wmk_your_key_here" \
-H "Content-Type: application/json" \
-d '{"url": "example.com"}'⚠️ Treat your API key like a password. Never commit it to source control or expose it in client-side code.
Run an audit
/api/v1/audit— Start a new auditBody parameters
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | required | URL to audit. Protocol optional (auto-prefixed with https://). |
| webhookUrl | string | optional | HTTPS URL to receive a POST when the audit fully completes (including background tasks). See Webhooks section. |
| options | object | optional | Advanced options. Available only to whitelisted accounts. See "Advanced options" below. |
Example request
curl -X POST https://webmatik.ai/api/v1/audit \
-H "X-API-Key: wmk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "stripe.com",
"webhookUrl": "https://your-app.com/webhooks/webmatik"
}'Response (202 Accepted)
{
"auditId": "afb1f027-7bcb-4b1c-abe8-c2a09d246c77",
"status": "processing",
"redirectTo": "/audit/afb1f027-7bcb-4b1c-abe8-c2a09d246c77"
}Save the auditId — you'll need it to fetch results.
Advanced options (whitelisted accounts only)
If your account is whitelisted, you can pass options to skip parts of the audit for faster, cheaper runs. Useful when you only need core scoring or have your own broken-link checker. Non-whitelisted accounts get a 403 if they try to use these flags.
{
"url": "client.com",
"options": {
"skipChecks": ["broken-links", "geo", "vision"],
"skipInnerPages": true
}
}| Field | Type | Required | Description |
|---|---|---|---|
| options.skipChecks | string[] | optional | Array of check IDs to skip. Allowed: "broken-links", "geo", "vision". |
| options.skipInnerPages | boolean | optional | If true, only the homepage is analyzed (no inner pages). |
Skipped checks won't appear in the response and won't affect the category score (treated as not applicable).
Get audit result
/api/v1/audit/{id}— Fetch audit status and resultPolling pattern
After starting an audit, poll this endpoint every 5–10 seconds until status === "completed". Audits typically finish in 60–180 seconds. Or use a webhook instead.
Status values
- •
processing— audit running. Continue polling. - •
completed— audit finished. Use the result. - •
failed— audit failed (timeout, network error, invalid URL).
Example request
curl https://webmatik.ai/api/v1/audit/afb1f027-7bcb-4b1c-abe8-c2a09d246c77 \
-H "X-API-Key: wmk_your_key_here"Response (completed)
{
"status": "completed",
"auditId": "afb1f027-7bcb-4b1c-abe8-c2a09d246c77",
"url": "https://stripe.com",
"score": 87.6,
"grade": "Excellent",
"siteType": "saas",
"language": "en",
"reportUrl": "https://webmatik.ai/audit/afb1f027-...",
"timestamp": "2026-04-26T12:34:56.000Z",
"summary": {
"conversion": { "score": 92, "passed": 8, "issues": 1, "topIssue": "..." },
"retention": { "score": 78, "passed": 5, "issues": 2, "topIssue": "..." },
"performance":{ "score": 85, "passed": 6, "issues": 2, "topIssue": "..." },
"uiux": { "score": 95, "passed": 10, "issues": 0, "topIssue": null },
"seo": { "score": 88, "passed": 18, "issues": 3, "topIssue": "..." },
"geo": { "score": 75, "passed": 4, "issues": 2, "topIssue": "..." },
"accessibility": { "score": 90, "passed": 9, "issues": 1, "topIssue": "..." },
"security": { "score": 80, "passed": 7, "issues": 2, "topIssue": "..." }
},
"actionPlan": {
"total": 13,
"critical": [
{
"category": "performance",
"title": "Reduce mobile LCP",
"description": "Largest Contentful Paint is 4.2s on mobile",
"howToFix": "Compress hero images and enable lazy loading...",
"effort": "medium",
"impact": "high"
}
],
"important": [...],
"niceToHave": [...]
},
"seo": {
"estimatedTraffic": 12500000,
"totalKeywords": 89500,
"topKeywords": [...]
},
"geoVisibility": {
"score": 75,
"promptsChecked": 16,
"mentionedIn": 12,
"citedIn": 8,
"providers": [...],
"queries": [...]
},
"innerPages": [...]
}Response (still processing)
{
"status": "processing",
"auditId": "afb1f027-...",
"url": "https://stripe.com",
"geoStatus": "pending",
"visionStatus": "complete",
"partialScore": 82.4,
"message": "Audit is finalizing background analysis..."
}Get audit as PDF
/api/v1/audit/{id}/pdf— Download audit report as PDFReturns the same audit report as a PDF binary. Useful for sending reports to clients, archiving, or attaching to tickets. Available on all paid plans.
Response
- •
Content-Type:application/pdf - •
Content-Disposition:attachment; filename="webmatik-{domain}-{grade}-{score}.pdf" - • Returns 409 if audit is still processing
Example: download PDF
curl -o report.pdf https://webmatik.ai/api/v1/audit/{id}/pdf \
-H "X-API-Key: $WEBMATIK_API_KEY"Webhooks
Instead of polling, pass a webhookUrl when starting an audit. We'll POST the full result to that URL when the audit completes (including background tasks like AI vision and GEO).
Requirements
- • Must be HTTPS (HTTP rejected)
- • Must respond with 2xx status within 10 seconds
- • Single delivery attempt — handle retries on your side if needed
- • Internal/private hosts (localhost, 10.x.x.x, *.local) are blocked
Headers sent
| Field | Type | Required | Description |
|---|---|---|---|
| X-Webmatik-Event | string | optional | Event type. Currently always "audit.completed". |
| X-Webmatik-Signature | string | optional | HMAC-SHA256 signature: "sha256=<hex>". Verify using your API key hash as secret. |
| Content-Type | string | optional | application/json |
Verifying the signature (Node.js)
import crypto from 'crypto';
function verifySignature(rawBody, signatureHeader, apiKeyHash) {
const expected = crypto
.createHmac('sha256', apiKeyHash)
.update(rawBody)
.digest('hex');
return signatureHeader === `sha256=${expected}`;
}Webhook payload
Same structure as the GET endpoint, with an additional event field.
{
"event": "audit.completed",
"auditId": "afb1f027-...",
"url": "https://stripe.com",
"score": 87.6,
"grade": "Excellent",
"summary": { ... },
"actionPlan": { ... }
}Error codes
| Field | Type | Required | Description |
|---|---|---|---|
| 400 | Bad Request | optional | Invalid URL, malformed JSON, or invalid webhookUrl |
| 401 | Unauthorized | optional | Missing or invalid X-API-Key header |
| 403 | Forbidden | optional | API access requires a Starter, Growth or Agency plan |
| 404 | Not Found | optional | Audit ID does not exist or belongs to different user |
| 429 | Too Many Requests | optional | Monthly audit limit reached for your plan |
| 500 | Server Error | optional | Unexpected server error — retry with exponential backoff |
Error response shape
{ "error": "Description of what went wrong" }Rate limits
There are no per-second rate limits, but the total number of audits per month is capped by your plan:
- • Starter: 10 / 25 / 50 audits per month (depending on tier)
- • Growth: 50 / 100 / 200 audits per month (depending on tier)
- • Agency: 100 audits per month, shared by the team
When you exceed the monthly limit, requests return 429 until the next billing cycle.
Code examples
Node.js (with polling)
const API_KEY = process.env.WEBMATIK_API_KEY;
const BASE = 'https://webmatik.ai/api/v1';
async function audit(url) {
// Start audit
const start = await fetch(`${BASE}/audit`, {
method: 'POST',
headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ url }),
});
const { auditId } = await start.json();
// Poll until complete
while (true) {
await new Promise(r => setTimeout(r, 8000));
const res = await fetch(`${BASE}/audit/${auditId}`, {
headers: { 'X-API-Key': API_KEY },
});
const result = await res.json();
if (result.status === 'completed') return result;
if (result.status === 'failed') throw new Error('Audit failed');
}
}
const result = await audit('stripe.com');
console.log(`Growth Score: ${result.score}/100 (${result.grade})`);
console.log(`Critical issues: ${result.actionPlan.critical.length}`);Python
import os, time, requests
API_KEY = os.environ['WEBMATIK_API_KEY']
BASE = 'https://webmatik.ai/api/v1'
H = {'X-API-Key': API_KEY}
def audit(url):
r = requests.post(f'{BASE}/audit', headers={**H, 'Content-Type': 'application/json'}, json={'url': url})
audit_id = r.json()['auditId']
while True:
time.sleep(8)
res = requests.get(f'{BASE}/audit/{audit_id}', headers=H).json()
if res['status'] == 'completed':
return res
if res['status'] == 'failed':
raise Exception('Audit failed')
result = audit('stripe.com')
print(f"Score: {result['score']}/100 ({result['grade']})")With webhook (no polling)
curl -X POST https://webmatik.ai/api/v1/audit \
-H "X-API-Key: $WEBMATIK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "stripe.com",
"webhookUrl": "https://your-app.com/webhooks/webmatik"
}'Need help? Contact us or check the step-by-step tutorial for using the API with AI coding tools.