REST API Reference
The NAT server exposes a REST API that lets you start scans, retrieve results, and manage your workspace programmatically. This is the same API used by the NAT CLI and dashboard. The API supports both security scanning and functional testing (visual regression, accessibility, and performance).
The REST API is available in both the SaaS hosted version (base URL: https://api.nat-testing.io/api/v1) and the self-hosted server (base URL: http://localhost:8080/api/v1).
Authentication
All API endpoints require authentication using an API key passed in the X-API-Key header:
X-API-Key: nat_pk_your_api_key_hereGenerate an API key from the dashboard under Settings → API Keys.
Base URL
| Deployment | Base URL |
|---|---|
| SaaS | https://api.nat-testing.io/api/v1 |
| Self-hosted | http://YOUR_HOST:PORT/api/v1 |
Scans
The scan endpoints support three modes:
| Mode | Description |
|---|---|
"security" | API security scan (OWASP API Top 10 and beyond) — default |
"functional" | Functional tests: visual regression, accessibility, Core Web Vitals |
"full" | Security + functional tests in a single run |
Start a scan
POST /scancurl -X POST https://api.nat-testing.io/api/v1/scan \
-H "X-API-Key: $NAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com",
"spec_url": "https://api.example.com/openapi.json",
"options": {
"concurrency": 5,
"timeout": 30
}
}'Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
url | string | ✅ | Target API base URL |
spec_url | string | OpenAPI/Swagger spec URL | |
spec_content | string | Base64-encoded spec content (alternative to spec_url) | |
auth.type | string | bearer, header, basic, oauth2, none | |
auth.token | string | Bearer token value | |
auth.header_name | string | Header name for header auth type | |
auth.header_value | string | Header value for header auth type | |
auth.username | string | Username for basic auth | |
auth.password | string | Password for basic auth | |
auth.oauth2_token_url | string | OAuth2 token endpoint | |
auth.oauth2_client_id | string | OAuth2 client ID | |
auth.oauth2_client_secret | string | OAuth2 client secret | |
auth.oauth2_scope | string | OAuth2 scopes | |
options.concurrency | integer | Parallel request count (default: 5) | |
options.timeout | integer | Per-request timeout seconds (default: 30) | |
options.fail_on | string | Severity level for non-zero exit: critical, high, medium, low | |
options.exclude | string[] | Path patterns to exclude from scanning |
Response 202 Accepted:
{
"scan_id": "scan_abc123xyz",
"status": "running",
"created_at": "2025-01-15T10:30:00Z"
}Get scan status
GET /scan/{scan_id}curl https://api.nat-testing.io/api/v1/scan/$SCAN_ID \
-H "X-API-Key: $NAT_API_KEY"Response 200 OK:
{
"scan_id": "scan_abc123xyz",
"status": "running",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:31:00Z"
}Status values: queued, running, completed, failed, cancelled
Get scan results
GET /scan/{scan_id}/resultscurl https://api.nat-testing.io/api/v1/scan/$SCAN_ID/results \
-H "X-API-Key: $NAT_API_KEY"Response 200 OK:
{
"status": "completed",
"passed": 10,
"failed": 2,
"total": 12,
"elapsed_seconds": 45.32
}Export results
GET /scan/{scan_id}/exportQuery parameters:
| Parameter | Values | Default |
|---|---|---|
format | html, json, csv | json |
# HTML report
curl "https://api.nat-testing.io/api/v1/scan/$SCAN_ID/export?format=html" \
-H "X-API-Key: $NAT_API_KEY" -o report.html
# JSON export
curl "https://api.nat-testing.io/api/v1/scan/$SCAN_ID/export?format=json" \
-H "X-API-Key: $NAT_API_KEY" -o results.json
# CSV export
curl "https://api.nat-testing.io/api/v1/scan/$SCAN_ID/export?format=csv" \
-H "X-API-Key: $NAT_API_KEY" -o results.csvList scans
GET /scanscurl "https://api.nat-testing.io/api/v1/scans" \
-H "X-API-Key: $NAT_API_KEY"Query parameters:
| Parameter | Description | Default |
|---|---|---|
page | Page number | 1 |
per_page | Results per page (max 100) | 20 |
status | Filter by status | All |
Response 200 OK:
{
"scans": [
{
"scan_id": "scan_abc123xyz",
"status": "completed",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:31:30Z"
}
],
"total": 47,
"page": 1,
"per_page": 20
}Get functional test results
GET /scan/{scan_id}/functional-resultsReturns the combined functional test results. Poll until status is completed.
curl https://api.nat-testing.io/api/v1/scan/$SCAN_ID/functional-results \
-H "X-API-Key: $NAT_API_KEY"Get visual regression report
GET /scan/{scan_id}/visual-regressionReturns before/after screenshots and pixel-diff analysis for each page tested.
curl https://api.nat-testing.io/api/v1/scan/$SCAN_ID/visual-regression \
-H "X-API-Key: $NAT_API_KEY"Get accessibility scan results
GET /scan/{scan_id}/accessibilityReturns WCAG violation details and per-page compliance scores.
curl https://api.nat-testing.io/api/v1/scan/$SCAN_ID/accessibility \
-H "X-API-Key: $NAT_API_KEY"Get performance metrics
GET /scan/{scan_id}/performanceReturns Core Web Vitals (LCP, FID, CLS, TTFB) and performance scores for each page.
curl https://api.nat-testing.io/api/v1/scan/$SCAN_ID/performance \
-H "X-API-Key: $NAT_API_KEY"The functional-results, visual-regression, accessibility, and performance endpoints are only available for scans started with "mode": "functional" or "mode": "full". See the Functional Testing API for full request/response schemas.
Usage
Get usage and quota
GET /usagecurl https://api.nat-testing.io/api/v1/usage \
-H "X-API-Key: $NAT_API_KEY"Response 200 OK:
{
"plan": "pro",
"functional_scans_used": 47,
"functional_scans_limit": 500,
"security_scans_used": 3,
"security_scans_limit": 100,
"approaching_limit": false,
"quota_reset_date": "2025-02-01T00:00:00Z"
}Get usage alerts
GET /usage/alertscurl https://api.nat-testing.io/api/v1/usage/alerts \
-H "X-API-Key: $NAT_API_KEY"Billing
Start a checkout session
POST /billing/checkoutcurl -X POST https://api.nat-testing.io/api/v1/billing/checkout \
-H "X-API-Key: $NAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"plan": "pro",
"success_url": "https://app.nat-testing.io/dashboard?upgraded=true",
"cancel_url": "https://app.nat-testing.io/dashboard"
}'Response 200 OK:
{
"checkout_url": "https://checkout.stripe.com/pay/cs_live_..."
}Redirect the user to checkout_url to complete payment.
Open billing portal
POST /billing/portalcurl -X POST https://api.nat-testing.io/api/v1/billing/portal \
-H "X-API-Key: $NAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"return_url": "https://app.nat-testing.io/dashboard"}'Response 200 OK:
{
"portal_url": "https://billing.stripe.com/session/..."
}Health
Health check
GET /healthcurl https://api.nat-testing.io/api/v1/healthResponse 200 OK:
{
"status": "ok"
}The /health endpoint does not require authentication and is safe to use for monitoring and uptime checks.
Errors
All errors follow RFC 7807 (Problem Details):
{
"error": "ERROR_CODE",
"message": "Human-readable description of what went wrong.",
"status": 400
}401 Unauthorized
Returned when the X-API-Key header is missing or the key is invalid.
curl https://api.nat-testing.io/api/v1/usage
# (no X-API-Key header){
"error": "INVALID_API_KEY",
"message": "The API key provided is invalid or has been revoked.",
"status": 401
}402 Payment Required
Returned when your monthly scan quota has been exceeded.
{
"error": "QUOTA_EXCEEDED",
"message": "You have reached your monthly scan quota. Upgrade your plan or wait for quota reset.",
"status": 402,
"quota_reset_date": "2025-02-01T00:00:00Z"
}Also returned when you attempt to use a feature not available on your current plan (e.g., security scans on the Free plan):
{
"error": "FEATURE_NOT_AVAILABLE",
"message": "Security scans are not available on the Free plan. Upgrade to Pro or above.",
"status": 402
}404 Not Found
Returned when the requested resource (e.g., scan ID) does not exist.
{
"error": "NOT_FOUND",
"message": "No scan found with ID scan_xyz123.",
"status": 404
}422 Unprocessable Entity
Returned when the request body fails validation.
{
"error": "VALIDATION_ERROR",
"message": "Field 'url' is required.",
"status": 422
}Common validation errors:
| Field | Error | Description |
|---|---|---|
url | VALIDATION_ERROR | Missing or not a valid URL |
spec_url | VALIDATION_ERROR | Not a valid URL |
format | VALIDATION_ERROR | Export format not one of html, json, csv |
plan | VALIDATION_ERROR | Plan name not one of free, pro, team, enterprise |
429 Too Many Requests
Returned when the rate limit for your plan is exceeded. Retry after the number of seconds specified in the Retry-After header.
{
"error": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please retry after 15 seconds.",
"status": 429
}Rate limits
| Plan | Requests per minute |
|---|---|
| Free | 10 |
| Pro | 60 |
| Team | 200 |
| Enterprise | 1,000 |
| Self-hosted | Unlimited |
Rate limit headers are included in all responses:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 115
X-RateLimit-Reset: 1705315800
Retry-After: 15The Retry-After header is only present on 429 responses and indicates the number of seconds to wait before retrying.