Guide

Welcome! This guide shows how to authenticate, submit scans, poll job status, and retrieve results (HTML, JSON, SARIF). All examples are ready to copy/paste.

Base URL & Auth

  • Base URL: https://api.craftedcybersolutions.com
  • Auth header: access-token: <YOUR_API_KEY>

Get an API key from the signup form on the main site, confirm your email, and keep the key safe.

Linux/macOS (bash)

# 1) set your key
export TOKEN="YOUR_API_KEY"

# 2) scan a public repo (HTTPS)
JOB=$(curl -s -H "access-token: $TOKEN" \
-X POST -d repo_url=https://github.com/pallets/flask \
https://api.craftedcybersolutions.com/v2/scan | jq -r .job_id)

# 3) poll until done
curl -s -H "access-token: $TOKEN" \
https://api.craftedcybersolutions.com/v2/status/$JOB | jq

# 4) fetch HTML report
curl -s -H "access-token: $TOKEN" \
-o /tmp/report.html https://api.craftedcybersolutions.com/v2/report/$JOB

# 5) fetch JSON report
curl -s -H "access-token: $TOKEN" \
"https://api.craftedcybersolutions.com/v2/report/$JOB?format=json" | jq

# 6) fetch SARIF 2.1.0
curl -s -H "access-token: $TOKEN" \
https://api.craftedcybersolutions.com/v2/report/$JOB/sarif | jq '.version, (.runs[0].results|length)'

Windows (PowerShell)

$env:TOKEN = "YOUR_API_KEY"

# Repo scan
$resp = Invoke-RestMethod `
-Headers @{ 'access-token' = $env:TOKEN } `
-Method Post -ContentType 'application/x-www-form-urlencoded' `
-Body @{ repo_url = 'https://github.com/pallets/flask' } `
-Uri 'https://api.craftedcybersolutions.com/v2/scan'
$job = $resp.job_id

# Poll
Invoke-RestMethod -Headers @{ 'access-token' = $env:TOKEN } `
-Uri "https://api.craftedcybersolutions.com/v2/status/$job"

# HTML report
$path = "$env:TEMP\scan-report.html"
Invoke-WebRequest -Headers @{ 'access-token' = $env:TOKEN } `
-Uri "https://api.craftedcybersolutions.com/v2/report/$job" -OutFile $path
Start-Process $path

Endpoints

1) Scan a public Git repo

POST /v2/scan
Content-Type: application/x-www-form-urlencoded
Header: access-token: <key>
Body: repo_url=https://example.com/owner/repo[.git]

Returns: { "job_id": "<uuid>" }

Notes:

  • Public https:// repositories only (no SSH).
  • The service performs a shallow clone (depth=1) and scans for secrets.

2) Upload a ZIP archive

POST /v2/scan/upload
Header: access-token: <key>
Body (multipart/form-data): archive=@/path/to/code.zip

Returns: { "job_id": "<uuid>" }

Notes:

  • Use a standard .zip (no nested symlinks outside the archive; zip-slip is blocked).
  • Typical limit: ~50 MB archives (you’ll get 413 if too large).
  • We scan the extracted files without relying on a Git history (--no-git mode).
(cd /path/to/project && zip -r /tmp/project.zip . -x '*.git*')
JOB=$(curl -s -H "access-token: $TOKEN" \
-F "archive=@/tmp/project.zip;type=application/zip" \
https://api.craftedcybersolutions.com/v2/scan/upload | jq -r .job_id)

3) Scan raw text/blobs

POST /v2/scan/text
Header: access-token: <key>
Content-Type: application/json
Body:
{
"content": "AWS_ACCESS_KEY_ID=AKIA... \nAWS_SECRET_ACCESS_KEY=....",
"filename": "secrets.env" // optional
}

Returns: { "job_id": "<uuid>" }

4) Check job status

GET /v2/status/{job_id}
Header: access-token: <key>

Example response:

{
"job_id": "…",
"status": "done", // queued | running | done | error
"severity_counts": { "low": 0, "med": 1, "high": 0, "crit": 0 },
"findings": 1
}

If status = error, check the error column (support can assist). Common messages include:

  • invalid_repo_url
  • clone_failed: … (bad URL, removed/renamed repo, or credentials required)
  • zip_slip_blocked

5) Retrieve reports

GET /v2/report/{job_id}
Header: access-token: <key>

GET /v2/report/{job_id}?format=json
Header: access-token: <key>

GET /v2/report/{job_id}/sarif
Header: access-token: <key>

Result schema (JSON)

Each finding is normalized with these fields:

{
"tool": "gitleaks", // scanner that found it
"rule_id": "github-pat", // detection rule
"severity": "med", // low | med | high | crit
"file": "path/to/file",
"line": 12,
"summary": "Short human summary",
"details": "Redacted or shortened secret value",
"ai_fix": "Safe remediation steps in plain English",
"false_positive_likelihood": 0.2
}

Severity & counts

We compute counts across low | med | high | crit and return them in /v2/status/{job_id}.

Rate limits & performance

  • Rate limit: bursts are throttled (HTTP 429). Start with ≤5 requests/sec per client and back-off on 429s.
  • Queueing: scans are background jobs; poll /v2/status/{job_id} until done.
  • Timeouts: large repos/archives take longer—poll every 2–5 seconds.

Security & privacy

  • Secrets in output are redacted by default where the underlying tool supports it.
  • We log request metadata (not bodies) and redact sensitive headers.
  • If you accidentally upload real secrets, rotate them immediately.
  • Need a data purge? Contact support with the job_id.

CI examples

GitHub Actions

name: Secrets Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Zip workspace
run: zip -r /tmp/work.zip . -x '*.git*'
- name: Submit scan
env:
TOKEN: ${{ secrets.CCS_API_TOKEN }}
run: |
JOB=$(curl -s -H "access-token: $TOKEN" \
-F "archive=@/tmp/work.zip;type=application/zip" \
https://api.craftedcybersolutions.com/v2/scan/upload | jq -r .job_id)
echo "JOB=$JOB" >> $GITHUB_ENV
- name: Wait for result
env: { TOKEN: ${{ secrets.CCS_API_TOKEN }} }
run: |
for i in {1..120}; do
S=$(curl -s -H "access-token: $TOKEN" https://api.craftedcybersolutions.com/v2/status/$JOB | jq -r .status)
[ "$S" = "done" ] && break
[ "$S" = "error" ] && exit 1
sleep 3
done
- name: Download SARIF
env: { TOKEN: ${{ secrets.CCS_API_TOKEN }} }
run: |
curl -s -H "access-token: $TOKEN" \
https://api.craftedcybersolutions.com/v2/report/$JOB/sarif \
-o results.sarif
- name: Upload SARIF to GitHub
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

Plain Bash script

#!/usr/bin/env bash
set -euo pipefail
TOKEN="${TOKEN:?Set TOKEN=your_api_key}"

zip -r /tmp/code.zip . -x '*.git*'
JOB=$(curl -s -H "access-token: $TOKEN" \
-F "archive=@/tmp/code.zip;type=application/zip" \
https://api.craftedcybersolutions.com/v2/scan/upload | jq -r .job_id)

until true; do
S=$(curl -s -H "access-token: $TOKEN" https://api.craftedcybersolutions.com/v2/status/$JOB | jq -r .status)
case "$S" in
done) break ;;
error) echo "Scan failed"; exit 1 ;;
esac
sleep 3
done

curl -s -H "access-token: $TOKEN" \
"https://api.craftedcybersolutions.com/v2/report/$JOB?format=json" | jq

Errors & troubleshooting

Symptom / CodeWhat it meansHow to fix
401 UnauthorizedMissing/invalid access-token headerSend your API key header
403 Quota ExceededFree plan monthly cap reached;Wait for next month or upgrade
405 Method Not AllowedWrong HTTP verbUse POST for scans
409 ConflictReport not readyWait for status=done before fetching report
413 Payload Too LargeZIP exceeds limitReduce size or contact support
422 Unprocessable EntityMissing/invalid fieldsCheck body format
429 Too Many RequestsRatelimitBack off and retry with jitter
clone_failed: …Bad repo URL, private repo, or removed repoUse a public https:// URL that exists
zip_slip_blockedUnsafe archive pathsRe-create the ZIP without ../ paths

Tip: Start with a known test repo like https://github.com/trufflesecurity/test-keys to verify your pipeline.

Usage & Limits

Check your usage (per key/owner)

Endpoints

  • GET /v2/usage/self → totals and recent activity
  • GET /v2/usage/self/monthly?months=12 → per-month breakdown (last N months)

Linux/macOS (bash)

# Current usage
curl -s -H "access-token: $TOKEN" \
https://api.craftedcybersolutions.com/v2/usage/self | jq

# Monthly breakdown (last 6 months)
curl -s -H "access-token: $TOKEN" \
"https://api.craftedcybersolutions.com/v2/usage/self/monthly?months=6" | jq

Windows (PowerShell)

# Current usage
Invoke-RestMethod -Headers @{ 'access-token' = $env:TOKEN } `
-Uri 'https://api.craftedcybersolutions.com/v2/usage/self' | ConvertTo-Json

# Monthly breakdown
Invoke-RestMethod -Headers @{ 'access-token' = $env:TOKEN } `
-Uri 'https://api.craftedcybersolutions.com/v2/usage/self/monthly?months=6' | ConvertTo-Json

Response examples

{
"owner": "[email protected]",
"total_jobs": 34,
"jobs_last_24h": 3,
"jobs_last_7d": 34,
"last_job_at_epoch": 1755094117,
"last_job_at_iso": "2025-08-13T14:08:37+00:00",
"cache_ttl_seconds": 300
}
[
{ "month": "2025-08", "jobs": 34 },
{ "month": "2025-07", "jobs": 12 }
]

Batch Scans

Endpoint

  • POST /v2/scan/batch
  • Header: access-token: <key>
  • Body: JSON { "repos": ["https://github.com/org/repo.git", ...] } (up to ~50)

Linux/macOS (bash)

curl -s -H "access-token: $TOKEN" -H "Content-Type: application/json" \
-d '{"repos":["https://github.com/pallets/flask.git","https://github.com/psf/requests.git"]}' \
https://api.craftedcybersolutions.com/v2/scan/batch | jq

Windows (PowerShell)

$body = @{ repos = @(
'https://github.com/pallets/flask.git',
'https://github.com/psf/requests.git'
)} | ConvertTo-Json
Invoke-RestMethod -Headers @{ 'access-token' = $env:TOKEN } `
-Method Post -ContentType 'application/json' -Body $body `
-Uri 'https://api.craftedcybersolutions.com/v2/scan/batch'

Returns

{ "jobs": {
"https://github.com/pallets/flask.git": "job-uuid-1",
"https://github.com/psf/requests.git": "job-uuid-2"
}}

Triage (noise reduction)

Add triage=true to JSON reports to down-rank obvious noise (playlist/JWT placeholders, low-entropy tokens, etc.).

Example

curl -s -H "access-token: $TOKEN" \
"https://api.craftedcybersolutions.com/v2/report/$JOB?format=json&triage=true" \
| jq 'group_by(.triage) | map({triage: .[0].triage, count: length})'

Triage labels

  • likely-fp — obvious false positives (severity auto-downgraded to low)
  • needs-review — everything else

Rate Limits & Quotas

Per-minute throttling (burst control)

  • Requests to POST /v2/scan and POST /v2/scan/batch are throttled per key/owner.
  • If exceeded: 429 Too Many Requests with body:
{ "detail": "rate limit: 20/60s" }
  • (Limit may vary; back off with jitter and retry.)

Monthly quota (free plan)

  • Free plan: 30 scans per calendar month (per owner).
  • On first exceed this month:
    • You’ll receive an email notification,
    • Your account is paused for the remainder of the month,
    • API returns:
{ "detail": "quota exceeded: account paused until month-end", "limit_month": 30 }
    • with HTTP 403.
  • Premium and admin are not subject to the monthly quota.
  • Auto-unpause at the start of a new UTC month.

How to monitor your usage

  • Use GET /v2/usage/self and GET /v2/usage/self/monthly (examples above).

Need higher limits or Premium access? Use the signup/contact on the main site and mention your key/email.

OpenAPI & Docs

  • Live ReDoc (public routes only):
    https://api.craftedcybersolutions.com/api-docs
  • Filtered OpenAPI JSON (public):
    https://api.craftedcybersolutions.com/openapi-public.json

Note: Only /signup* and /v2/* appear in the public schema; internal/admin routes are not exposed.