Scan API
Endpoints for submitting repository scans, polling for results, retrieving reports, checking deep scan quota, and submitting finding feedback.
POST /api/scan
/api/scan
No auth required (anonymous) or API key
Submit a repository for scanning. The API validates the URL, checks rate limits, deducts one credit (for authenticated users), creates a scan record, and asynchronously invokes the scan Lambda. Returns immediately with a scan_id and status pending.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
repo_url | string | Yes | Full GitHub repository URL (e.g. https://github.com/owner/repo). Must be a public repository. |
deep | boolean | No | Set to true to request a deep scan. Requires sufficient credits and a passing deep scan rate limit check. Default: false. |
Response (202 Accepted)
{
"scan_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"repo_url": "https://github.com/owner/repo",
"scan_type": "shallow"
}
Error responses
| Status | Condition |
|---|---|
| 400 | Missing or invalid repo_url |
| 402 | Insufficient credits for authenticated user |
| 429 | Rate limit exceeded (1 shallow scan / 24h per IP, or 3 deep scans / 7-day rolling per IP) |
Example
curl -X POST https://api.ticketyboo.dev/api/scan \
-H "Content-Type: application/json" \
-d '{"repo_url": "https://github.com/owner/repo", "deep": false}'
GET /api/scan/{id}
/api/scan/{id}
No auth required
Get scan status and findings. Poll this endpoint after submitting a scan. When status is complete, the findings array is populated.
Path parameters
| Parameter | Description |
|---|---|
id | Scan ID returned by POST /api/scan |
Response (200 OK)
{
"scan_id": "550e8400-e29b-41d4-a716-446655440000",
"repo_url": "https://github.com/owner/repo",
"status": "complete",
"scan_type": "shallow",
"created_at": "2026-03-31T12:00:00Z",
"findings": [...],
"summary": {
"critical": 0,
"high": 1,
"medium": 3,
"low": 2,
"info": 0,
"total": 6
},
"gatekeep": {
"verdict": "passed",
"gates_evaluated": 2,
"gates_fired": 0
}
}
The gatekeep field is null when no devcontract.json was found in the repository.
GET /api/scan/{id}/report
/api/scan/{id}/report
No auth required
Retrieve the full scan report from S3. Includes the complete finding list with all fields, Gatekeep gate-by-gate breakdown, and scan metadata. The report is stored at reports/{scan_id}/report.json in the ticketyboo-reports-579378699130 bucket and proxied through this endpoint.
Error responses
| Status | Condition |
|---|---|
| 404 | Scan not found, or scan not yet complete |
GET /api/scan/deep-quota
/api/scan/deep-quota
No auth required
Returns the number of deep scans remaining for the calling IP address in the current 7-day rolling window. The limit is 3 per IP per 7 days.
Response (200 OK)
{
"remaining": 2,
"limit": 3,
"window_days": 7
}
POST /api/scan/{id}/feedback
/api/scan/{id}/feedback
JWT or API key required
Submit a human verdict on a specific finding. Feedback is written to the scanner-feedback DynamoDB table and aggregated by the learning loop to adjust finding confidence scores in future scans.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
finding_id | string | Yes | The finding ID from the scan result |
verdict | string | Yes | correct or incorrect |
notes | string | No | Optional free-text notes |
Response (200 OK)
{"status": "ok"}
GET /api/scan/{id}/feedback
/api/scan/{id}/feedback
JWT or API key required
Retrieve all feedback submitted for a scan. Returns an array of feedback records.
Response (200 OK)
{
"feedback": [
{
"finding_id": "e5f6a7b8",
"verdict": "correct",
"notes": "Confirmed: this was a real secret.",
"submitted_at": "2026-03-31T12:10:00Z"
}
]
}