Home/Docs/API Reference

API Reference

Integrate WordPress security scanning into your workflow. Authenticate with API keys, stream scan results in real-time, and automate security audits.

Base URL: /apiv1.0

Authentication

All API requests require authentication via a Bearer token. Create API keys from your dashboard.Keys use the format wpss_<32 hex chars>.

Header
Authorization: Bearer wpss_your_api_key_here
cURL Examplebash
curl -H "Authorization: Bearer wpss_abc123..." \
  "https://your-domain.com/api/scan/stream?url=https://example.com"
JavaScript Examplejavascript
const response = await fetch(
  "https://your-domain.com/api/scan/stream?url=https://example.com",
  {
    headers: {
      Authorization: "Bearer wpss_abc123..."
    }
  }
);

// Parse Server-Sent Events
const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const text = decoder.decode(value);
  console.log(text);
}

Key Format

wpss_<32 hex>

Keys start with wpss_ prefix

Rate Limiting

Per-key limits

Configurable daily limits

Revocation

Instant

Revoke anytime from dashboard


Rate Limits

Rate limits depend on authentication. Guests have per-IP limits; authenticated users have per-key daily limits.

TypePer-MinutePer-Day
Guest10 req/minPlan-based
Session User10 req/minPlan limit
API Key10 req/minKey-specific

Rate Limit Headers

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1709827200
Retry-After: 42          # Only on 429 responses

GET/api/scan/stream

Stream Scan

Stream a full security scan via Server-Sent Events. Returns real-time progress as each of 36 scanners completes. This is the recommended endpoint for most integrations.

Parameters

ParameterTypeDescription
urlstringFull URL to scan (https://example.com). Must be root domain, no path.

SSE Events

EventDescription
startScan initialized — includes totalScanners and scanner list
scanner:startIndividual scanner starting — includes scanner name
scanner:completeScanner finished — includes name and issueCount
completeFull scan result with score, issues, plugins, SSL, and durationMs

Example Response

SSE Streamtext
event: start
data: {"totalScanners":33,"scanners":[{"name":"ssl","displayName":"SSL/TLS Certificate","category":"network"},...]}

event: scanner:start
data: {"name":"ssl"}

event: scanner:complete
data: {"name":"ssl","issueCount":0}

event: scanner:start
data: {"name":"headers"}

event: scanner:complete
data: {"name":"headers","issueCount":2}

...

event: complete
data: {"url":"https://example.com","score":72,"issues":[...],"passedChecks":[...],"durationMs":4521}

POST/api/scan

Single Scan

Run a full scan and return results as a single JSON response. Simpler than streaming but no progress updates.

Request Body

ParameterTypeDescription
urlstringFull URL to scan (https://example.com). Must be root domain.
cURLbash
curl -X POST \
  -H "Authorization: Bearer wpss_abc123..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}' \
  "https://your-domain.com/api/scan"
Responsejson
{
  "url": "https://example.com",
  "score": 72,
  "issues": [
    {
      "id": "missing-csp",
      "severity": "high",
      "title": "Missing Content-Security-Policy",
      "description": "No CSP header detected...",
      "recommendation": "Add a Content-Security-Policy header..."
    }
  ],
  "passedChecks": [...],
  "detectedPlugins": [...],
  "detectedTheme": {...},
  "sslAnalysis": {...},
  "scannedAt": "2026-03-07T12:00:00.000Z"
}

GET/api/scan/bulk

Bulk Scan

Scan up to 20 sites concurrently with streaming progress. Runs 3 concurrent scans at a time.

Pro / Enterprise plans only

Parameters

ParameterTypeDescription
urlsstringComma-separated URLs (max 20 or plan limit)

SSE Events

EventDescription
startBulk scan initialized — totalUrls and urlList
url:startIndividual URL scan starting — urlIndex and url
url:scanner:completeScanner finished for a URL — urlIndex, scannerName, issueCount
url:completeURL scan complete — urlIndex, url, and full result
allCompleteAll scans done — totalUrls, completedUrls, averageScore, results[]
cURLbash
curl -H "Authorization: Bearer wpss_abc123..." \
  "https://your-domain.com/api/scan/bulk?urls=https://site1.com,https://site2.com,https://site3.com"

GET/api/scan/compare

Compare Two Sites

Compare two sites side-by-side. Both URLs are scanned in parallel and results include score diffs and unique issues.

Pro / Enterprise plans only

Parameters

ParameterTypeDescription
url1stringFirst URL to compare
url2stringSecond URL to compare

SSE Events

EventDescription
startComparison initialized — scanner list
scanner:startScanner starting for one site — name and scanIndex (0 or 1)
scanner:completeScanner finished — name, issueCount, scanIndex
completeOne site scan complete — scanIndex and full result with durationMs
allCompleteBoth scans complete — comparison ready
cURLbash
curl -H "Authorization: Bearer wpss_abc123..." \
  "https://your-domain.com/api/scan/compare?url1=https://site1.com&url2=https://site2.com"

GET/api/scan/check-limit

Check Scan Quota

Check remaining scan quota for the current API key, session, or guest IP. Does not consume a scan.

cURLbash
curl -H "Authorization: Bearer wpss_abc123..." \
  "https://your-domain.com/api/scan/check-limit"
Responsejson
{
  "allowed": true,
  "remaining": 87,
  "isGuest": false
}

Note: remaining: -1 means unlimited scans. remaining: 0 means the daily limit has been reached.


API Key Management

Admin endpoints for creating, listing, updating, and revoking API keys. All require admin session authentication.

POST/api/keysCreate a new API key
ParameterTypeDescription
namestringKey name (max 200 chars)
dailyLimitnumberMax scans per day (default: 100)
expiresAtISO 8601Optional expiration datetime
Responsejson
{
  "id": "clx1abc...",
  "name": "CI Pipeline Key",
  "keyPrefix": "wpss_a1b",
  "dailyLimit": 100,
  "expiresAt": null,
  "createdAt": "2026-03-07T12:00:00.000Z",
  "key": "wpss_a1b2c3d4e5f6..."  // Returned ONCE — save it!
}
GET/api/keysList all API keys

Returns all keys with usage stats. Full key hash is never returned — only the prefix is shown.

PATCH/api/keys/[id]Update key name or limit
ParameterTypeDescription
namestringNew key name (max 200 chars)
dailyLimitnumberNew daily scan limit (positive integer)
DELETE/api/keys/[id]Revoke an API key (soft delete)

Sets the key to inactive. The key cannot be reactivated — create a new one instead.


Response Format

The complete event (streaming) or JSON response (POST) returns this structure.

Scan Resultjson
{
  "url": "https://example.com",
  "score": 72,
  "issues": [
    {
      "id": "missing-csp",
      "severity": "high",
      "title": "Missing Content-Security-Policy",
      "description": "No CSP header detected...",
      "recommendation": "Add a Content-Security-Policy header...",
      "scanner": "headers",
      "category": "headers"
    }
  ],
  "passedChecks": [
    {
      "scanner": "ssl",
      "displayName": "SSL/TLS Certificate",
      "description": "Valid certificate with 240 days remaining"
    }
  ],
  "detectedPlugins": [
    {
      "name": "Contact Form 7",
      "version": "5.8.4",
      "vulnerable": false,
      "vulnerabilities": []
    }
  ],
  "detectedTheme": {
    "name": "Flavflavor flavor flavored",
    "slug": "flavor",
    "version": "3.2.1",
    "isChild": false,
    "parentTheme": null
  },
  "sslAnalysis": {
    "isValid": true,
    "issuer": "Let's Encrypt",
    "daysUntilExpiry": 240,
    "protocol": "TLSv1.3",
    "selfSigned": false
  },
  "scannedAt": "2026-03-07T12:00:00.000Z",
  "durationMs": 4521
}

Issue Severity Levels

critical

Immediate action needed

high

Should fix soon

medium

Moderate risk

low

Informational


Error Codes

All errors return a JSON object with an error field.

Error Responsejson
{
  "error": "Missing or invalid URL"
}
CodeMeaning
400Bad Request
401Unauthorized
403Forbidden
422Validation Error
429Rate Limited
500Server Error

URL Validation Rules

All scan endpoints validate URLs against these rules:

  • Protocol must be http:// or https://
  • Must be root domain only (no path, e.g. https://example.com not https://example.com/page)
  • Private IP ranges blocked (10.x, 172.16-31.x, 192.168.x, 127.x, ::1, etc.)
  • Localhost scanning is forbidden
  • URL must resolve to a valid domain