perf-lint API
Base URL: https://perflint.martkos-it.co.uk/api
Rate limits: Free 50 scans/month · Pro 500 scans/month · Team unlimited
Authentication: X-API-Key: your-api-key (required for Pro/Team; optional for free tier within rate limits)
Lint a script file
Section titled “Lint a script file”POST /api/lintContent-Type: multipart/form-data
file=@my-test.jmxtool=jmeterOr with API key and explicit options:
curl -X POST https://perflint.martkos-it.co.uk/api/lint \ -H "X-API-Key: ${PERF_LINT_API_KEY}" \ -F "file=@my-test.jmx" \ -F "tool=jmeter" \ -F "format=json"Parameters:
| Param | Required | Values | Description |
|---|---|---|---|
file | Yes | — | Script file (.jmx, .js, .scala) |
tool | No | jmeter, k6, gatling, auto | Default: auto (detected from file extension) |
format | No | json, sarif, text | Default: json |
rules | No | comma-separated rule IDs | Only run these rules |
severity | No | error, warn, info | Minimum severity to report |
Lint script content (JSON body)
Section titled “Lint script content (JSON body)”POST /api/lint/contentContent-Type: application/json
{ "content": "import http from 'k6/http';\n...", "tool": "k6", "filename": "load-test.js"}Response (JSON format)
Section titled “Response (JSON format)”{ "tool": "k6", "filename": "load-test.js", "summary": { "total": 3, "errors": 1, "warnings": 1, "info": 1 }, "findings": [ { "ruleId": "K6001", "severity": "error", "message": "sleep() missing between requests — add think time to simulate realistic user behaviour", "line": 12, "column": 1, "fix": { "available": true, "description": "Add sleep(1) after request" } }, { "ruleId": "K6005", "severity": "warn", "message": "No threshold defined — add thresholds to options to enforce SLAs", "line": 3, "column": 1, "fix": { "available": false } } ], "exitCode": 1, "scansUsed": 1, "scansRemaining": 499}Response (SARIF format)
Section titled “Response (SARIF format)”{ "version": "2.1.0", "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", "runs": [ { "tool": { "driver": { "name": "perf-lint", "version": "1.x", "rules": [...] } }, "results": [...] } ]}Upload SARIF to GitHub Advanced Security for in-PR lint annotations:
- name: Upload SARIF uses: github/codeql-action/upload-sarif@v3 with: sarif_file: lint-results.sarifList available rules
Section titled “List available rules”GET /api/rules?tool=jmeter&tier=communityParameters:
| Param | Values | Description |
|---|---|---|
tool | jmeter, k6, gatling | Filter by tool |
tier | community, pro, team | Filter by tier availability |
severity | error, warn, info | Filter by severity |
Response:
[ { "id": "JMX001", "tool": "jmeter", "severity": "warn", "tier": "community", "title": "Thread group uses \"Forever\" loop", "description": "Set a finite loop count or duration to prevent unbounded test runs.", "fixable": true, "docsUrl": "https://perflint.martkos-it.co.uk/rules/JMX001" }]Get rule detail
Section titled “Get rule detail”GET /api/rules/{ruleId}Team Configuration (Team Tier)
Section titled “Team Configuration (Team Tier)”Get team config
Section titled “Get team config”GET /api/team/configX-API-Key: your-team-keyReturns the shared .perf-lint.yml configuration applied to all scans using this team API key.
Update team config
Section titled “Update team config”PUT /api/team/configX-API-Key: your-team-keyContent-Type: application/json
{ "rules": { "JMX001": "off", "K6005": "warn" }, "ignore": ["tests/legacy/**"]}Usage stats
Section titled “Usage stats”GET /api/team/usage?month=2026-03Response:
{ "month": "2026-03", "scans": 312, "limit": null, "topErrors": [ {"ruleId": "JMX010", "count": 87}, {"ruleId": "K6001", "count": 64} ]}Error Responses
Section titled “Error Responses”| Status | Meaning |
|---|---|
400 | Bad request (unsupported file type, parse failure) |
401 | Invalid or missing API key |
413 | File too large (max 10MB) |
422 | Validation error |
429 | Rate limit exceeded |
500 | Internal error |
Rate limit error:
{ "error": "RATE_LIMIT_EXCEEDED", "message": "Monthly scan limit reached (50/50). Upgrade to Pro for 500 scans/month.", "scansUsed": 50, "resetAt": "2026-04-01T00:00:00Z"}