Audit Endpoints

Submit repo audits, poll status, view quota, and manage history for the repo-audit feature.

Audit Endpoints

The audit API powers the /audit feature — submit a public GitHub URL, get a Markdown critique plus a place in the knowledge graph.

All endpoints are rooted at /api/demo/. See the audit guide for the end-to-end flow.

POST/api/demo/audit

Submit a repo for audit. Clerk token optional — anonymous callers get 1/day per hashed IP; signed-in callers get 5/day.

Rate limit: 10/minute per caller

Request body

{
  "repo_url": "https://github.com/owner/repo",
  "publish_consent": true
}
FieldTypeRequiredDescription
repo_urlstringYesPublic GitHub URL. Normalized server-side (trailing slash, .git suffix, lowercase host).
publish_consentbooleanYesMust be true. Audits are public by default.

Response — new audit 202

{
  "audit_id": "3f2a7b8e-...",
  "status": "queued"
}

Response — deduped 200

If the caller already has a complete audit for this URL in the last 24 hours:

{
  "audit_id": "3f2a7b8e-...",
  "status": "complete",
  "deduped": true
}

Error responses

StatusMeaning
400publish_consent missing, or repo_url not a valid GitHub URL
429Daily quota exceeded ("quota exceeded: 5/5 today")
503Global concurrency cap reached (3 in-flight) — includes Retry-After: 60 header
GET/api/demo/audit/{audit_id}

Poll for audit status and results. No auth required.

Rate limit: 120/minute per caller

Response 200

{
  "audit_id": "3f2a7b8e-...",
  "repo_url": "https://github.com/owner/repo",
  "status": "complete",
  "stage": "complete",
  "neighbors": [
    { "entity_id": "repo-other", "title": "...", "score": 0.89 }
  ],
  "markdown": "## Review\n\n...",
  "error": null,
  "entity_id": "repo-owner-repo",
  "created_at": "2026-04-20T13:45:12+00:00"
}

Possible status values: queued, ingesting, indexing, critiquing, complete, failed.

Responses include Cache-Control: no-store — clients should poll rather than cache.

GET/api/demo/audit/quota

Return the caller's current daily quota usage.

Rate limit: 60/minute per caller

Response 200

{
  "limit": 5,
  "used": 2,
  "resets_at": "2026-04-21T13:45:12+00:00"
}

For anonymous callers, limit is 1 and used counts audits against the hashed IP. Quota windows are rolling 24 hours, not calendar days.

GET/api/demo/audit/history

Return the signed-in user's past audits, newest first. Requires Clerk Bearer token.

Rate limit: 30/minute per caller

Response 200

[
  {
    "audit_id": "3f2a7b8e-...",
    "repo_url": "https://github.com/owner/repo",
    "status": "complete",
    "entity_id": "repo-owner-repo",
    "created_at": "2026-04-20T13:45:12+00:00"
  }
]

Returns up to 200 most recent audits for the authenticated user. Anonymous audits (submitted before signing in) aren't included — they're keyed to IP hash, not user ID.

DELETE/api/demo/audit/{audit_id}

Delete an audit and remove its entity from the knowledge graph. Requires Clerk Bearer token — must be the original submitter.

Rate limit: 30/minute per caller

Response 200

{ "deleted": true }

Errors

StatusMeaning
403Audit belongs to a different user
404Audit ID not found

The delete is two-phase: the audit row is removed from Postgres, then kb-api is called to purge the corresponding entity and its embeddings. A kb-api failure doesn't block the Postgres delete — orphan entities get cleaned up by a periodic reconciler.