Skip to main content

Scan API

Endpoints for submitting repository scans, polling for results, retrieving reports, checking deep scan quota, and submitting finding feedback.

POST /api/scan

POST /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

FieldTypeRequiredDescription
repo_urlstringYesFull GitHub repository URL (e.g. https://github.com/owner/repo). Must be a public repository.
deepbooleanNoSet 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

StatusCondition
400Missing or invalid repo_url
402Insufficient credits for authenticated user
429Rate 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}

GET /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

ParameterDescription
idScan 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

GET /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

StatusCondition
404Scan not found, or scan not yet complete

GET /api/scan/deep-quota

GET /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

POST /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

FieldTypeRequiredDescription
finding_idstringYesThe finding ID from the scan result
verdictstringYescorrect or incorrect
notesstringNoOptional free-text notes

Response (200 OK)

{"status": "ok"}

GET /api/scan/{id}/feedback

GET /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"
    }
  ]
}