Developer API · v1

Security scans, scriptable.

Start scans from CI, poll results, and pull audit reports — everything the dashboard does for scanning and reporting, over plain HTTPS + JSON.

Authentication

Create an API key in dashboard settings → API keys. The full key (vg_live_…) is shown exactly once — we store only its hash. Send it on every request as the X-API-Key header.

curl "$VIBEGUARD_API/v1/scans/$SCAN_ID" \
  -H "X-API-Key: vg_live_…"

Keys carry three scopes: scans:read, scans:write, and reports:read. Revoking a key (settings, one click) disables it immediately.

Base URL

All v1 endpoints live on the VibeGuard API origin — the same https://api.… host your dashboard talks to. The examples below use $VIBEGUARD_API as a stand-in for that origin. Requests are HTTPS-only; bodies and responses are JSON (UTF-8).

Endpoints

Five endpoints, all ownership-scoped to the account that owns the key. The typical flow: create a scan → upload the ZIP → start → poll until complete → (purchase an audit in the dashboard) → poll the audit → fetch the report.

POST/v1/scansscans:write

Create a project + scan. For ZIP sources the response includes a signed upload URL — PUT your archive there, then call start. Counts toward the per-key daily scan limit.

Parameters

  • project_name (body · string, required)Display name, 1–200 chars.
  • source_type (body · string, required)"zip" or "github".
  • github_repo_full_name (body · string, optional)For "github" sources, e.g. "acme/storefront". The repo must have the VibeGuard GitHub App installed (done once from the dashboard).

Response

201 Created
{
  "scan_id": "8b6c…",
  "project_id": "f1d2…",
  "upload_url": "https://…signed…",   // null for github sources
  "upload_storage_path": "raw-uploads/…/….zip",  // null for github
  "upload_expires_at": "2026-06-12T10:15:00Z"    // 15 minutes
}

Example

curl -X POST "$VIBEGUARD_API/v1/scans" \
  -H "X-API-Key: $VIBEGUARD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_name": "my-mvp", "source_type": "zip"}'

# then upload the archive (ZIP sources only):
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: application/zip" \
  --data-binary @my-mvp.zip

Creating an API key constitutes your standing authorization to scan code you own or are authorized to scan — the same commitment the dashboard checkbox records. Your account email must be verified.

POST/v1/scans/{scan_id}/startscans:write

Queue the scan for processing. Call after the ZIP upload completes (or immediately for GitHub sources). Returns 409 if the scan already left the queued state.

Parameters

  • scan_id (path · uuid)From the create response.

Response

202 Accepted
{
  "scan_id": "8b6c…",
  "status": "queued"
}

Example

curl -X POST "$VIBEGUARD_API/v1/scans/$SCAN_ID/start" \
  -H "X-API-Key: $VIBEGUARD_API_KEY"
GET/v1/scans/{scan_id}scans:read

Scan status plus the full findings list once complete — the same shape the dashboard polls. Findings are empty until status is complete.

Parameters

  • scan_id (path · uuid)The scan to inspect.

Response

200 OK
{
  "id": "8b6c…",
  "status": "queued | extracting | scanning | complete | failed",
  "source_type": "zip | github",
  "project_id": "f1d2…",
  "total_files": 412, "included_files": 268, "ignored_files": 144,
  "risky_skipped_files": 0, "total_bytes": 9182733, "included_bytes": 4201554,
  "complexity_score": 42.5, "complexity_label": "moderate",
  "launch_readiness_score": 61.0,
  "free_findings_summary": { "findings_by_severity": { "critical": 1, … } },
  "created_at": "…", "completed_at": "… | null", "error_message": null,
  "findings": [
    {
      "id": "…", "severity": "critical", "category": "secret",
      "rule_id": "…", "title": "…", "description": "…",
      "recommendation": "… | null", "file_path": "src/db.ts",
      "line_start": 12, "line_end": 14,
      "masked_evidence": "sk_live_****", "confidence": "high"
    }
  ]
}

Example

curl "$VIBEGUARD_API/v1/scans/$SCAN_ID" \
  -H "X-API-Key: $VIBEGUARD_API_KEY"
GET/v1/audits/{audit_job_id}reports:read

Status of a purchased audit run, including the security-fix pull request URL once it opens. Audits are purchased in the dashboard; this endpoint observes them.

Parameters

  • audit_job_id (path · uuid)Shown in the dashboard after purchase.

Response

200 OK
{
  "audit_job_id": "c9a1…",
  "status": "queued | running | … | completed | failed",
  "tier": "launch_check | founder_shield | elite_audit",
  "pr_url": "https://github.com/acme/storefront/pull/42"  // null until open
}

Example

curl "$VIBEGUARD_API/v1/audits/$AUDIT_JOB_ID" \
  -H "X-API-Key: $VIBEGUARD_API_KEY"
GET/v1/audits/{audit_job_id}/reportreports:read

The full report payload — markdown, severity overview, signed download URLs (PDF, fixed-files bundle), and the PR link. Identical to the dashboard report viewer response.

Parameters

  • audit_job_id (path · uuid)The purchased audit run.

Response

200 OK
{
  "audit_job_id": "c9a1…",
  "status": "ready | pending | failed",
  "title": "…", "tier": "founder_shield",
  "report_markdown": "# VibeGuard audit…",
  "files": { "pdf": { "name": "VIBEGUARD_REPORT.pdf", "url": "https://…signed…" } },
  "fixed_files_url": "https://…signed… | null",  // patch bundle (folder uploads)
  "pr_url": "https://github.com/… | null",       // GitHub deliveries
  "findings_by_severity": { "critical": 1, "high": 4, "medium": 9, "low": 3, "info": 2 },
  "total_findings": 19,
  "launch_readiness_score": 61.0,
  "fix_count": 14
}

Example

curl "$VIBEGUARD_API/v1/audits/$AUDIT_JOB_ID/report" \
  -H "X-API-Key: $VIBEGUARD_API_KEY"

Signed URLs in the response expire after about an hour — fetch the report again for fresh links rather than storing them.

Rate limits

  • 60 requests / minute per key — every v1 endpoint counts toward this bucket.
  • 20 scans / day per key — only POST /v1/scans counts.

Exceeding a limit returns 429 with the bucket name in the detail. Windows are fixed (UTC minute / UTC day), so a simple retry after the window boundary is enough — no jittered backoff required. Account-level abuse protections (per-user and per-IP scan limits) also still apply.

Errors

Errors are JSON with a single detail string (FastAPI convention). Validation failures on request bodies return 422 with field-level details.

401Missing, malformed, invalid, or revoked X-API-Key.
{ "detail": "Invalid or revoked API key." }
403Key lacks the required scope, or email verification / IP checks failed.
{ "detail": "This API key is missing the required scope 'scans:write'." }
404The resource does not exist or is not owned by your account (we never reveal which).
{ "detail": "Scan not found" }
429A per-key rate limit was exceeded. Back off and retry after the window resets.
{ "detail": "Rate limit exceeded (v1_requests_per_key_per_minute: 61/60). Try again later." }

Payments stay in the dashboard

There are deliberately no checkout, quote, or payment endpoints in v1. Purchasing an audit is an interactive, PayPal-approved step that happens in the dashboard — an API key can observe scans and fetch reports, but it can never spend your money.

Key hygiene

Treat keys like passwords: keep them in your CI secret store, never commit them, and rotate by creating a new key and revoking the old one. Key creation, usage timestamps, and revocation are all recorded in your account's activity log.

The cheapest time to fix security is before launch.

Run a free scan in under two minutes. See your launch-readiness score, top risks, and dynamic audit options instantly.

No credit card required for the free scan. Paid quotes generated only after the scan completes.