API Reference
REST API Reference

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_here

Generate an API key from the dashboard under Settings → API Keys.

Base URL

DeploymentBase URL
SaaShttps://api.nat-testing.io/api/v1
Self-hostedhttp://YOUR_HOST:PORT/api/v1

Scans

The scan endpoints support three modes:

ModeDescription
"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 /scan
curl -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:

FieldTypeRequiredDescription
urlstringTarget API base URL
spec_urlstringOpenAPI/Swagger spec URL
spec_contentstringBase64-encoded spec content (alternative to spec_url)
auth.typestringbearer, header, basic, oauth2, none
auth.tokenstringBearer token value
auth.header_namestringHeader name for header auth type
auth.header_valuestringHeader value for header auth type
auth.usernamestringUsername for basic auth
auth.passwordstringPassword for basic auth
auth.oauth2_token_urlstringOAuth2 token endpoint
auth.oauth2_client_idstringOAuth2 client ID
auth.oauth2_client_secretstringOAuth2 client secret
auth.oauth2_scopestringOAuth2 scopes
options.concurrencyintegerParallel request count (default: 5)
options.timeoutintegerPer-request timeout seconds (default: 30)
options.fail_onstringSeverity level for non-zero exit: critical, high, medium, low
options.excludestring[]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}/results
curl 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}/export

Query parameters:

ParameterValuesDefault
formathtml, json, csvjson
# 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.csv

List scans

GET /scans
curl "https://api.nat-testing.io/api/v1/scans" \
  -H "X-API-Key: $NAT_API_KEY"

Query parameters:

ParameterDescriptionDefault
pagePage number1
per_pageResults per page (max 100)20
statusFilter by statusAll

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-results

Returns 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-regression

Returns 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}/accessibility

Returns 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}/performance

Returns 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 /usage
curl 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/alerts
curl https://api.nat-testing.io/api/v1/usage/alerts \
  -H "X-API-Key: $NAT_API_KEY"

Billing

Start a checkout session

POST /billing/checkout
curl -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/portal
curl -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 /health
curl https://api.nat-testing.io/api/v1/health

Response 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:

FieldErrorDescription
urlVALIDATION_ERRORMissing or not a valid URL
spec_urlVALIDATION_ERRORNot a valid URL
formatVALIDATION_ERRORExport format not one of html, json, csv
planVALIDATION_ERRORPlan 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

PlanRequests per minute
Free10
Pro60
Team200
Enterprise1,000
Self-hostedUnlimited

Rate limit headers are included in all responses:

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 115
X-RateLimit-Reset: 1705315800
Retry-After: 15

The Retry-After header is only present on 429 responses and indicates the number of seconds to wait before retrying.

Was this helpful?