Resources
Troubleshooting
Common API Errors

Common API Errors

This page explains the most common HTTP error responses returned by the NAT API, their causes, and how to fix them.


401 Unauthorized

Error code: UNAUTHORIZED

HTTP/1.1 401 Unauthorized
Content-Type: application/json
 
{
  "error": "UNAUTHORIZED",
  "message": "Missing or invalid API key."
}

Causes

  • The X-API-Key header is missing from the request
  • The API key is invalid, expired, or belongs to a deleted tenant
  • The key was copied incorrectly (extra whitespace, truncated)

Fix

  1. Ensure the X-API-Key header is present on every request:
    curl https://api.nat-testing.io/api/v1/usage \
      -H "X-API-Key: nat_pk_your_api_key_here"
  2. Verify the key starts with nat_pk_ and matches what is shown in the dashboard (opens in a new tab) under Settings → API Keys.
  3. Do not use Authorization: Bearer — NAT uses X-API-Key exclusively.
  4. If the key was revoked, generate a new one from the dashboard.
⚠️

Never commit your API key to source control. Store it as an environment variable or in a secrets manager and reference it at runtime.


402 Payment Required

Error code: QUOTA_EXCEEDED

HTTP/1.1 402 Payment Required
Content-Type: application/json
 
{
  "error": "QUOTA_EXCEEDED",
  "message": "Monthly scan quota exhausted. Quota resets on 2025-02-01.",
  "quota_reset_date": "2025-02-01T00:00:00Z"
}

Causes

  • Your monthly functional or security scan quota is fully consumed
  • You are on the Free plan and have used all 50 functional scans for this period

Fix

Option 1 — Wait for the reset date. Quota resets automatically on the first day of each billing period. Check your reset date:

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

The quota_reset_date field contains the exact ISO 8601 timestamp.

Option 2 — Upgrade your plan for an immediate quota increase:

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"
  }'

Or upgrade directly via the dashboard (opens in a new tab) under Settings → Billing → Upgrade Plan.

In-flight scans are not interrupted when quota is exhausted — only new scan requests are blocked. See Pricing & Plans for quota details by plan.


429 Too Many Requests

Error code: RATE_LIMITED

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 12
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
 
{
  "error": "RATE_LIMITED",
  "message": "Rate limit exceeded. Retry after 12 seconds.",
  "retry_after": 12
}

Causes

  • You have exceeded your plan's per-minute request rate limit
  • Automated polling loops running too aggressively

Fix

  1. Respect the Retry-After header. Back off for the number of seconds specified before retrying.
  2. Reduce polling frequency. When polling scan status, use a reasonable interval (5–10 seconds) rather than tight loops.
  3. Upgrade your plan for a higher rate limit:
PlanRequests/minute
Free30
Pro120
Team300
Enterprise1,000

Example: exponential back-off in Python

import time
import requests
 
def poll_with_backoff(scan_id, api_key, max_retries=10):
    base_url = "https://api.nat-testing.io/api/v1"
    headers = {"X-API-Key": api_key}
    delay = 5
 
    for attempt in range(max_retries):
        r = requests.get(f"{base_url}/scan/{scan_id}", headers=headers)
        if r.status_code == 429:
            retry_after = int(r.headers.get("Retry-After", delay))
            print(f"Rate limited. Waiting {retry_after}s...")
            time.sleep(retry_after)
            delay = min(delay * 2, 60)
            continue
        r.raise_for_status()
        data = r.json()
        if data["status"] in ("completed", "failed", "cancelled"):
            return data
        time.sleep(delay)
 
    raise TimeoutError("Scan did not complete within max retries")

503 Service Unavailable

Error code: STRIPE_NOT_CONFIGURED (self-hosted only)

HTTP/1.1 503 Service Unavailable
Content-Type: application/json
 
{
  "error": "STRIPE_NOT_CONFIGURED",
  "message": "Billing is not configured on this server. Set STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET."
}

Causes

  • You are self-hosting NAT and the Stripe environment variables are not set
  • This error only appears on billing endpoints (/api/v1/billing/*) in self-hosted deployments

Fix

Set the required Stripe environment variables on your server:

STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_ID_PRO=price_...
STRIPE_PRICE_ID_TEAM=price_...

See the Self-Hosted Setup guide for a full list of required environment variables.

On the NAT Cloud (SaaS), this error will never appear — Stripe is pre-configured. You will only encounter 503 STRIPE_NOT_CONFIGURED when running a self-hosted NAT instance without billing configured.


Other errors

StatusCodeDescription
400 Bad RequestINVALID_REQUESTMalformed JSON or missing required fields. Check the request body.
403 ForbiddenFEATURE_NOT_AVAILABLEFeature not available on your current plan (e.g., security scans on Free). Upgrade to access.
404 Not FoundNOT_FOUNDThe scan ID does not exist or belongs to another tenant.
500 Internal Server ErrorINTERNAL_ERRORUnexpected server error. Retry after a short delay. If it persists, contact support.

See also

Was this helpful?