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.
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
}
| Field | Type | Required | Description |
|---|---|---|---|
repo_url | string | Yes | Public GitHub URL. Normalized server-side (trailing slash, .git suffix, lowercase host). |
publish_consent | boolean | Yes | Must 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
| Status | Meaning |
|---|---|
400 | publish_consent missing, or repo_url not a valid GitHub URL |
429 | Daily quota exceeded ("quota exceeded: 5/5 today") |
503 | Global concurrency cap reached (3 in-flight) — includes Retry-After: 60 header |
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.
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.
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 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
| Status | Meaning |
|---|---|
403 | Audit belongs to a different user |
404 | Audit 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.
Related
- Audit guide — UI flow, quotas, stages
- Knowledge API — how completed audits are queried back out