POST /api/static/scan
Trigger a new security scan for a specific repository and branch.
Request
Headers:
x-api-key (required): Your Rafter security API key
Content-Type: application/json
Body:
{
"repository_name": "myorg/myrepo",
"branch_name": "main",
"scan_mode": "fast",
"github_token": "github_pat_..."
}
The github_token field is optional. When omitted, the scan uses the OAuth credentials linked to your Rafter account. Use this field for scanning private repositories without OAuth — the token only needs Contents:Read permission.
Fields:
| Field | Type | Required | Description |
|---|
repository_name | string | Yes | Repository name in format org/repo |
branch_name | string | Yes | Branch name to scan |
scan_mode | string | No | Scan mode: "fast" (default) or "plus". Fast uses industry-standard tooling and Rafter’s proprietary analysis for SAST, secret detection, and dependency checks. Plus runs the full fast pipeline plus additional agent-driven analysis passes for deeper coverage. |
github_token | string | No | Fine-grained GitHub PAT for scanning private repositories. Only needs Contents:Read permission. Can also be set via RAFTER_GITHUB_TOKEN environment variable when using the CLI. |
Example Request
curl -X POST \
-H "Content-Type: application/json" \
-H "x-api-key: RFabc-your-api-key-here" \
-d '{
"repository_name": "myorg/myrepo",
"branch_name": "main",
"scan_mode": "fast"
}' \
https://rafter.so/api/static/scan
Response
Success (200 OK):
{
"success": true,
"scan_id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Error (400 Bad Request):
{
"error": "Missing required field: repository_name"
}
Error (401 Unauthorized):
{
"error": "Invalid or inactive API key."
}
Error (403 Forbidden — scan limit reached):
{
"error": "You have reached your Plus scan limit for this billing period.",
"scan_mode": "plus",
"used": 1,
"limit": 1
}
Error (403 Forbidden — insufficient scope):
{
"error": "API key does not have scan scope."
}
Error (429 Too Many Requests):
{
"error": "Rate limit exceeded. Please try again later."
}
The CLI maps this to exit code 3 (quota exhausted).
Error (404 Not Found):
{
"error": "Repository not found or access denied."
}
Error (500 Internal Server Error):
{
"error": "An unexpected error occurred."
}
Response Fields
| Field | Type | Description |
|---|
success | boolean | Whether the scan was successfully triggered |
scan_id | string | Unique identifier for the scan request |
Rate Limiting
The API implements rate limiting to ensure fair usage:
- Rate Limit: 100 requests per minute per IP address
- Quota: Based on your subscription plan
Examples
JavaScript
const response = await fetch('https://rafter.so/api/static/scan', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'RFabc-your-api-key-here'
},
body: JSON.stringify({
repository_name: 'myorg/myrepo',
branch_name: 'main',
scan_mode: 'fast'
})
});
const data = await response.json();
console.log(`Scan ID: ${data.scan_id}`);
Python
import requests
response = requests.post(
'https://rafter.so/api/static/scan',
headers={
'Content-Type': 'application/json',
'x-api-key': 'RFabc-your-api-key-here'
},
json={
'repository_name': 'myorg/myrepo',
'branch_name': 'main',
'scan_mode': 'fast'
}
)
data = response.json()
print(f"Scan ID: {data['scan_id']}")
Next Steps
After triggering a scan, you can:
- Check scan status using the
scan_id with the Get Results endpoint
- Wait for completion by polling the status endpoint
- Retrieve results once the scan is complete
Workflow Example
# 1. Trigger scan
SCAN_ID=$(curl -X POST \
-H "Content-Type: application/json" \
-H "x-api-key: RFabc-your-api-key-here" \
-d '{"repository_name": "myorg/myrepo", "branch_name": "main", "scan_mode": "fast"}' \
https://rafter.so/api/static/scan | jq -r '.scan_id')
# 2. Wait for completion (polling)
MAX_ATTEMPTS=15
for i in $(seq 1 $MAX_ATTEMPTS); do
RESPONSE=$(curl -fsS -H "x-api-key: $API_KEY" \
"https://rafter.so/api/static/scan?scan_id=$SCAN_ID")
STATUS=$(echo $RESPONSE | jq -r '.status')
if [ "$STATUS" = "completed" ]; then
echo "Scan completed!"
echo $RESPONSE | jq '.vulnerabilities | length' | xargs echo "Found vulnerabilities:"
break
elif [ "$STATUS" = "failed" ]; then
echo "Scan failed!"
echo $RESPONSE | jq -r '.error'
exit 1
else
echo "Attempt $i/$MAX_ATTEMPTS: Status is $STATUS"
sleep 10
fi
done
# 3. Get results
curl -H "x-api-key: RFabc-your-api-key-here" \
"https://rafter.so/api/static/scan?scan_id=$SCAN_ID"