API Reference

Complete reference for every Vergate REST endpoint. Base URL: https://api.vergate.dev

For an interactive API explorer, see Swagger UI and ReDoc. The full machine-readable spec is at /openapi.json.

Note. All examples use curl. Replace pk_your_key with your real API key. Create one at https://vergate.dev/project/{project_id}/settings.

#Base URL

https://api.vergate.dev

#Authentication

Every authenticated endpoint accepts either of these:

MethodHeaderExample
API KeyAuthorization: Bearer pk_...curl -H "Authorization: Bearer pk_abc123" ...
API Key (alt)X-API-Key: pk_...curl -H "X-API-Key: pk_abc123" ...
Session cookiesession=<JWT>Set automatically on login/signup (browser only)

API keys are project-scoped: each key is locked to one project. List only that project's scans. Create multiple keys per project, revoke independently.

Caution. The raw key (pk_...) is shown only once at creation. Copy it immediately — it is never stored, only a SHA-256 hash.

#Error Responses

Errors return a JSON body with detail and an HTTP status code:

401 Unauthorized
{
  "detail": "Invalid API key"
}
StatusMeaning
401Missing or invalid API key / session
403Valid auth but insufficient plan or not admin
404Resource not found (project, scan, target)
409Conflict (e.g. duplicate project URL)
422Validation error (invalid body, bad URL, bad interval)
502Upstream dependency unavailable (Lighthouse, Umami, GlitchTip)

#Projects

A project is a website you want to scan. Each project has a unique URL, scan history, monitoring targets, and integrations.

#Create Project

POST /api/v1/projects
curl -X POST https://api.vergate.dev/api/v1/projects \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Website",
    "url": "https://example.com",
    "description": "Main marketing site"
  }'
Response — 201
{
  "id": "a1b2c3d4-...",
  "name": "My Website",
  "url": "https://example.com",
  "description": "Main marketing site",
  "created_at": "2026-08-17T10:00:00Z"
}

#List Projects

GET /api/v1/projects
curl https://api.vergate.dev/api/v1/projects \
  -H "Authorization: Bearer pk_your_key"
Response — 200
{
  "projects": [
    {
      "id": "a1b2c3d4-...",
      "name": "My Website",
      "url": "https://example.com",
      "scan_count": 5,
      "latest_scan": { "status": "completed", ... }
    }
  ]
}
Tip. Project-scoped API keys return only their own project from this endpoint.

#Get Project

GET /api/v1/projects/{id}
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-... \
  -H "Authorization: Bearer pk_your_key"

#Delete Project

DELETE /api/v1/projects/{id}
curl -X DELETE https://api.vergate.dev/api/v1/projects/a1b2c3d4-... \
  -H "Authorization: Bearer pk_your_key"
Caution. This permanently deletes the project and all its scan history.

#Scanning

Scans run in two phases: passive (fast, inline, security headers + profiling + perf + SEO + AEO + accessibility) then active (ZAP, queued to a background worker, ~10-20s).

#Start Unified Scan

Runs all 6 modules on a single row. This is the primary scan command.

POST /api/v1/projects/{id}/scan
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../scan \
  -H "Authorization: Bearer pk_your_key"
Response — 202
{
  "scan_ids": {
    "passive": "scan-uuid-here",
    "unified": "scan-uuid-here"
  },
  "status": "pending"
}

#Start Scan with Custom Modules

Choose which modules to run. Free-tier users automatically get ["security", "profiling"].

POST /api/v1/projects/{id}/scans
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../scans \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "run_modules": ["security", "profiling", "performance"]
  }'

#List Scans

GET /api/v1/projects/{id}/scans
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../scans \
  -H "Authorization: Bearer pk_your_key"

#Get Scan Details

GET /api/v1/projects/{id}/scans/{scan_id}
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../scans/scan-uuid \
  -H "Authorization: Bearer pk_your_key"

#Get Scan Results

Returns findings, module scores, profile data, and progress. Use this to poll until status is "completed".

GET /api/v1/projects/{id}/scans/{scan_id}/results
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../scans/scan-uuid/results \
  -H "Authorization: Bearer pk_your_key"
Response — 200
{
  "status": "completed",
  "findings": [
    {
      "id": "...",
      "title": "Missing Content-Security-Policy header",
      "severity": "medium",
      "likelihood": "observed",
      "description": "...",
      "remediation": "..."
    }
  ],
  "profile_result": { "detections": [...] },
  "seo_result": { "score": 85, "issues": [...] },
  "performance_result": { "overall_score": 92, ... },
  "accessibility_result": { "score": 80, ... }
}
Note. The first scan on a new target reports everything as "new". Subsequent scans show only actual changes.

#Download Report (PDF / JSON)

Reports are tamper-evident: the PDF gets a signed verification page, the JSON embeds a verification object, and both carry an X-Vergate-Verification header.

GET /api/v1/projects/{id}/scans/{scan_id}/download?format=pdf
curl -o report.pdf \
  "https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../scans/scan-uuid/download?format=pdf" \
  -H "Authorization: Bearer pk_your_key"

Use format=json for raw machine-readable output.

#Cancel Scan

DELETE /api/v1/projects/{id}/scans/{scan_id}
curl -X DELETE https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../scans/scan-uuid \
  -H "Authorization: Bearer pk_your_key"

#Standalone Analysis

These run inline (no background queue) and return results immediately. Each takes 5-30 seconds depending on the check.

#Performance (Lighthouse)

POST /api/v1/projects/{id}/performance
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../performance \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "form_factor": "desktop"
  }'
Response — 200
{
  "overall_score": 92,
  "metrics": [
    { "name": "Largest Contentful Paint", "value": "1.1s", "rating": "good" },
    { "name": "Total Blocking Time", "value": "22ms", "rating": "good" }
  ],
  "opportunities": [...],
  "http_checks": [...]
}

#SEO / AEO Analysis

POST /api/v1/projects/{id}/seo
# SEO mode
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../seo \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "mode": "seo"}'

# AEO mode (AI search optimization)
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../seo \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "mode": "aeo"}'

#Accessibility (axe-core)

POST /api/v1/projects/{id}/accessibility
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../accessibility \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
Response — 200
{
  "score": 85,
  "violations": [
    {
      "impact": "serious",
      "id": "color-contrast",
      "description": "Elements must have sufficient color contrast",
      "help_url": "https://dequeuniversity.com/rules/axe/...",
      "nodes": [{ "target": [".hero-text"], "html": "..." }]
    }
  ]
}

#Technology Profiling

POST /api/v1/projects/{id}/profile
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../profile \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
Response — 200
{
  "detections": [
    { "technology": "Next.js", "confidence": 0.95, "version": "15.3" },
    { "technology": "Vercel", "confidence": 0.85 },
    { "technology": "React", "confidence": 0.9 }
  ]
}

#Email Deliverability

POST /api/v1/projects/{id}/deliverability
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../deliverability \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com"}'

#Download Analysis Report

Standalone analysis results (SEO, AEO, performance, accessibility) can be downloaded as PDF:

GET /api/v1/projects/{id}/analysis/{job_id}/download?format=pdf
curl -o seo-report.pdf \
  "https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../analysis/job-uuid/download?format=pdf" \
  -H "Authorization: Bearer pk_your_key"

#Monitoring (Uptime)

Continuous uptime monitoring with threat re-scanning. Targets are checked at your chosen interval (15 min to 7 days depending on plan).

#Create Monitoring Target

POST /api/v1/projects/{id}/monitoring
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "name": "Homepage",
    "scan_enabled": true,
    "scan_interval": 360
  }'
Note. scan_interval is in minutes. Allowed values depend on your plan: Starter [360], Pro [360, 720, 1440], Max [15–10080].

#List Targets

GET /api/v1/projects/{id}/monitoring
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring \
  -H "Authorization: Bearer pk_your_key"

#Update Target

PATCH /api/v1/projects/{id}/monitoring/{target_id}
curl -X PATCH https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring/target-uuid \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"scan_interval": 720, "scan_enabled": true}'

#Delete Target

DELETE /api/v1/projects/{id}/monitoring/{target_id}
curl -X DELETE https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring/target-uuid \
  -H "Authorization: Bearer pk_your_key"

#Trigger Immediate Scan

POST /api/v1/projects/{id}/monitoring/{target_id}/scan
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring/target-uuid/scan \
  -H "Authorization: Bearer pk_your_key"
Response — 202
{
  "status": "queued",
  "target_id": "target-uuid"
}

#Check History

GET /api/v1/projects/{id}/monitoring/{target_id}/checks
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring/target-uuid/checks \
  -H "Authorization: Bearer pk_your_key"

#Threat Scan History

GET /api/v1/projects/{id}/monitoring/{target_id}/threat-scans
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring/target-uuid/threat-scans \
  -H "Authorization: Bearer pk_your_key"

#Download Monitoring Report

GET /api/v1/projects/{id}/monitoring/{target_id}/download?format=pdf
curl -o uptime-report.pdf \
  "https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../monitoring/target-uuid/download?format=pdf" \
  -H "Authorization: Bearer pk_your_key"

#Badges

Issue a "Verified" trust badge for a project. Requires 0 critical findings in the latest scan. The badge is a JWT that third-party sites can verify to prove your site is clean.

#Issue Badge

POST /api/v1/projects/{id}/badges
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../badges \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com"}'
Response — 200
{
  "badge_id": "bdg_xxx",
  "token": "eyJhbGci...",
  "embed_code": "<script src=\"https://api.vergate.dev/badge.js\" data-token=\"eyJhbGci...\"></script>",
  "verify_url": "https://api.vergate.dev/badge/verify/eyJhbGci..."
}

#List Badges

GET /api/v1/projects/{id}/badges
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../badges \
  -H "Authorization: Bearer pk_your_key"

#Verify Badge (Public)

No authentication required. Anyone can verify a badge to check if a site is still clean.

GET /api/v1/badge/verify/{token}
curl https://api.vergate.dev/api/v1/badge/verify/eyJhbGci...

#Integrations

Connect third-party services (GitHub, Vercel, Cloudflare, etc.) and run security checks on their configurations.

#List Providers

GET /api/v1/integrations/providers
curl https://api.vergate.dev/api/v1/integrations/providers \
  -H "Authorization: Bearer pk_your_key"

#List Connections

GET /api/v1/integrations/connections
curl https://api.vergate.dev/api/v1/integrations/connections \
  -H "Authorization: Bearer pk_your_key"

#Create Integration

POST /api/v1/integrations
curl -X POST https://api.vergate.dev/api/v1/integrations \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "vercel",
    "label": "My Vercel",
    "credentials": { "token": "your_vercel_token" }
  }'

#Run Security Scan

Scans all connected providers (or a single one) for security misconfigurations.

POST /api/v1/integrations/scan
# Scan all connected providers
curl -X POST https://api.vergate.dev/api/v1/integrations/scan \
  -H "Authorization: Bearer pk_your_key"

# Scan a specific provider
curl -X POST https://api.vergate.dev/api/v1/integrations/scan/cloudflare \
  -H "Authorization: Bearer pk_your_key"

#Account Authentication

These endpoints manage user accounts and sessions. For programmatic access, prefer API keys (see Authentication).

#Sign Up

POST /api/v1/auth/signup
curl -X POST https://api.vergate.dev/api/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com",
    "password": "securepassword123",
    "name": "Your Name"
  }'
Note. All new accounts require email verification. A verification link is sent to your inbox.

#Log In

POST /api/v1/auth/login
curl -X POST https://api.vergate.dev/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com",
    "password": "securepassword123"
  }' \
  -c cookies.txt  # saves the session cookie

#Log Out

POST /api/v1/auth/logout
curl -X POST https://api.vergate.dev/api/v1/auth/logout \
  -b cookies.txt

#Get Current User

GET /api/v1/auth/me
curl https://api.vergate.dev/api/v1/auth/me -b cookies.txt
Response — 200
{
  "id": "uuid",
  "email": "you@example.com",
  "name": "Your Name",
  "plan": "pro",
  "is_paid": true,
  "projects_remaining": 8,
  "project_limit": 12,
  "weekly_health_email": true,
  "theme_pref": "dark"
}

#Update Profile

PATCH /api/v1/auth/me
curl -X PATCH https://api.vergate.dev/api/v1/auth/me \
  -H "Content-Type: application/json" \
  -b cookies.txt \
  -d '{
    "name": "New Name",
    "avatar_url": "https://example.com/avatar.png",
    "theme_pref": "dark"
  }'

#OAuth (Social Sign-in)

Redirects to the provider's login page. Supported providers: google, microsoft, github.

GET /api/v1/auth/oauth/{provider}/authorize
# Redirects to Google sign-in
curl -v https://api.vergate.dev/api/v1/auth/oauth/google/authorize

# For account linking (add ?link=1 when already logged in)
curl -v "https://api.vergate.dev/api/v1/auth/oauth/github/authorize?link=1" \
  -b cookies.txt

#Billing

#List Plans

GET /api/v1/billing/plans
curl https://api.vergate.dev/api/v1/billing/plans
Response — 200
{
  "plans": [
    {
      "id": "free",
      "name": "Free",
      "projects_limit": 1,
      "scans_per_month": 3,
      "monthly_price": 0,
      "annual_price": 0,
      "features": ["1 project", "3 passive scans/mo", "MCP support"]
    },
    {
      "id": "starter",
      "name": "Starter",
      "monthly_price": 2000,
      "annual_price": 20000,
      ...
    }
  ]
}

Prices are in cents (e.g. 2000 = $20.00/mo).

#Create Checkout Session

POST /api/v1/billing/checkout
curl -X POST https://api.vergate.dev/api/v1/billing/checkout \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "price_pro_monthly_uuid",
    "interval": "monthly"
  }'
Response — 200
{
  "checkout_url": "https://sandbox.polar.sh/checkout?..."
}

Redirect the user to checkout_url to complete payment on Polar.

#Customer Portal

Opens the Polar customer portal where users can manage their subscription, update payment methods, and view invoices.

POST /api/v1/billing/portal
curl -X POST https://api.vergate.dev/api/v1/billing/portal \
  -H "Authorization: Bearer pk_your_key"

#Early Access Offer

GET /api/v1/billing/early-access
curl https://api.vergate.dev/api/v1/billing/early-access
Response — 200 (when active)
{
  "active": true,
  "percent_off": 25,
  "duration_months": 2,
  "ends_at": "2026-09-01T00:00:00Z"
}

#Free Scans (No Auth)

Anonymous users can run up to 3 passive scans per IP address. No account required.

#Start Free Scan

POST /api/v1/free-scan
curl -X POST https://api.vergate.dev/api/v1/free-scan \
  -H "Content-Type: application/json" \
  -d '{"target_url": "https://example.com"}'
Response — 202
{
  "id": "free-scan-uuid",
  "status": "pending",
  "message": "Scan started"
}

#Check Status

GET /api/v1/free-scan/{id}/status
curl https://api.vergate.dev/api/v1/free-scan/free-scan-uuid/status

#Get Results

GET /api/v1/free-scan/{id}/results
curl https://api.vergate.dev/api/v1/free-scan/free-scan-uuid/results

#Report Verification

Every downloaded report includes a tamper-evident signature. Anyone can verify a report has not been altered.

#Verify Report

POST /api/v1/reports/verify
curl -X POST https://api.vergate.dev/api/v1/reports/verify \
  -H "Content-Type: application/json" \
  -d '{"token": "sha256.signature_hex"}'
Response — 200 (valid)
{
  "valid": true,
  "message": "Report signature verified"
}
GET (query param)
curl "https://api.vergate.dev/api/v1/reports/verify?token=sha256.signature_hex"

#Analysis Report Downloads

Standalone analysis results can be downloaded as branded PDFs.

EndpointFormat
GET /api/v1/projects/{id}/scans/{scan_id}/downloadPDF or JSON
GET /api/v1/projects/{id}/analysis/{job_id}/downloadPDF or JSON (SEO/AEO/perf/a11y)
GET /api/v1/projects/{id}/code-scans/{scan_id}/downloadPDF or JSON
GET /api/v1/projects/{id}/monitoring/{target_id}/downloadPDF or JSON

Add ?format=pdf or ?format=json to switch formats. PDF is the default.

#Project-Scoped API Keys

Create API keys that are locked to a single project. Scoped keys can only access their own project — all other projects return 404.

#Create Key

POST /api/v1/projects/{id}/mcp-key
curl -X POST https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../mcp-key \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "CI/CD Pipeline"}'
Response — 200
{
  "id": "key-uuid",
  "name": "CI/CD Pipeline",
  "api_key": "pk_scoped_abc123...",
  "created_at": "2026-08-17T10:00:00Z"
}
Caution. The api_key value is shown only once. Copy it now.

#List Keys

GET /api/v1/projects/{id}/mcp-key
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../mcp-key \
  -H "Authorization: Bearer pk_your_key"

#Revoke Key

DELETE /api/v1/projects/{id}/mcp-key/{key_id}
curl -X DELETE https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../mcp-key/key-uuid \
  -H "Authorization: Bearer pk_your_key"

#Code Scans (GitHub)

Analyzes GitHub Actions workflows for hardcoded secrets, unpinned actions, excessive permissions, and dangerous patterns. Requires a connected GitHub integration.

#List Code Scans

GET /api/v1/projects/{id}/code-scans
curl https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../code-scans \
  -H "Authorization: Bearer pk_your_key"

#Download Code Scan Report

GET /api/v1/projects/{id}/code-scans/{scan_id}/download?format=pdf
curl -o code-report.pdf \
  "https://api.vergate.dev/api/v1/projects/a1b2c3d4-.../code-scans/scan-uuid/download?format=pdf" \
  -H "Authorization: Bearer pk_your_key"

#Health Check

No authentication required. Returns service status for load balancers and monitoring.

GET /health
curl https://api.vergate.dev/health
Response — 200
{
  "status": "ok",
  "version": "..."
}

#OpenAPI Spec

The full machine-readable API spec is available in OpenAPI 3.1 JSON format.

URLDescription
/openapi.jsonFull OpenAPI 3.1 spec (machine-readable)
/docsInteractive Swagger UI explorer
/redocReDoc API reference
/llms.txtPlain-text API summary for AI crawlers

#Rate Limits

The scanner uses a semaphore of 50 concurrent HTTP requests per scan (configurable). API endpoints have no explicit rate limits but the background worker processes one ZAP active scan at a time per pool.

#Webhooks

Polar sends payment events to POST /api/v1/webhooks/polar. These are handled automatically — you don't need to call them.

EventWhat Happens
subscription.createdOrg plan activated, Subscription row created
subscription.updatedPlan/interval synced to DB
subscription.canceledSubscription marked canceled at period end
order.paidOne-time payment processed

#Quick Reference

Copy-paste these to get started fast.

#Full Scan → Poll → Download

bash
API="https://api.vergate.dev"
KEY="pk_your_key_here"

# 1. Create project
PROJECT_ID=$(curl -s -X POST "$API/api/v1/projects" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Site", "url": "https://example.com"}' | jq -r '.id')

# 2. Start scan
SCAN_ID=$(curl -s -X POST "$API/api/v1/projects/$PROJECT_ID/scan" \
  -H "Authorization: Bearer $KEY" | jq -r '.scan_ids.unified')

# 3. Poll until complete
while true; do
  STATUS=$(curl -s "$API/api/v1/projects/$PROJECT_ID/scans/$SCAN_ID/results" \
    -H "Authorization: Bearer $KEY" | jq -r '.status')
  echo "Status: $STATUS"
  [ "$STATUS" = "completed" ] && break
  sleep 3
done

# 4. Download PDF
curl -o report.pdf "$API/api/v1/projects/$PROJECT_ID/scans/$SCAN_ID/download?format=pdf" \
  -H "Authorization: Bearer $KEY"

echo "Report saved to report.pdf"

#Quick Technology Profile

bash
curl -X POST https://api.vergate.dev/api/v1/projects/{id}/profile \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}' | jq '.detections[] | .technology'

#Quick SEO Check

bash
curl -X POST https://api.vergate.dev/api/v1/projects/{id}/seo \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "mode": "seo"}' | jq '{score, issues: (.issues | length)}'