Skip to main content

Error Reference

Complete reference of Need2Watch API error codes with HTTP status codes, descriptions, common causes, and solutions.

Error Response Format

All API errors follow this structure:

{
"error": "Human-readable error message",
"code": "ERR_MACHINE_READABLE_CODE",
"message": "Additional context (optional)"
}

Example:

{
"error": "Limit exceeded",
"code": "ERR_LIMIT_EXCEEDED",
"message": "Free tier: 10 monitors maximum. Upgrade at /pricing"
}

Authentication Errors (401)

ERR_UNAUTHORIZED

HTTP Status: 401 Unauthorized

Description: Authentication failed or missing credentials.

Common Causes:

  • Missing Authorization header
  • Missing X-API-Key header
  • Invalid or expired JWT token
  • Invalid API key
  • API key revoked

Solutions:

# Option 1: Use API key
curl https://api.need2.watch/v1/monitors \
-H "X-API-Key: n2w_live_xxxxx"

# Option 2: Use JWT bearer token
curl https://api.need2.watch/v1/monitors \
-H "Authorization: Bearer eyJhbGci..."

Example Response:

{
"error": "Invalid credentials",
"code": "ERR_UNAUTHORIZED"
}

ERR_INVALID_REFRESH_TOKEN

HTTP Status: 401 Unauthorized

Description: Refresh token is invalid or expired.

Common Causes:

  • Refresh token expired (7 days)
  • Token was manually revoked via logout
  • Token never existed

Solutions:

  • Login again to obtain new tokens
  • Use API keys instead (recommended for long-lived access)

Example Response:

{
"error": "Invalid or expired refresh token",
"code": "ERR_INVALID_REFRESH_TOKEN"
}

Validation Errors (400)

ERR_INVALID_REQUEST

HTTP Status: 400 Bad Request

Description: Request validation failed.

Common Causes:

  • Missing required fields
  • Invalid field types
  • Invalid field values
  • Malformed JSON

Solutions:

  • Check required fields are present
  • Verify field types match API spec
  • Ensure JSON is valid

Example Response:

{
"error": "Validation failed",
"code": "ERR_INVALID_REQUEST",
"message": "intent is required for nlp mode"
}

ERR_INVALID_EMAIL

HTTP Status: 400 Bad Request

Description: Email format is invalid.

Common Causes:

  • Missing @ symbol
  • Invalid domain
  • Whitespace in email

Solutions:

{
"email": "user@example.com" // ✓ Valid
}

Example Response:

{
"error": "Invalid email format",
"code": "ERR_INVALID_EMAIL"
}

ERR_WEAK_PASSWORD

HTTP Status: 400 Bad Request

Description: Password does not meet security requirements.

Requirements:

  • Minimum 8 characters
  • At least one uppercase letter
  • At least one lowercase letter
  • At least one number

Solutions:

{
"password": "SecurePassword123!" // ✓ Valid
}

Example Response:

{
"error": "Password must be at least 8 characters and include uppercase, lowercase, and number",
"code": "ERR_WEAK_PASSWORD"
}

ERR_EMAIL_EXISTS

HTTP Status: 400 Bad Request

Description: Email already registered.

Common Causes:

  • Attempting to register with existing email
  • User already has an account

Solutions:

  • Use login endpoint instead: POST /auth/login
  • Use password reset if forgotten
  • Use different email

Example Response:

{
"error": "Email already registered",
"code": "ERR_EMAIL_EXISTS"
}

Resource Not Found (404)

ERR_NOT_FOUND

HTTP Status: 404 Not Found

Description: Requested resource does not exist.

Common Causes:

  • Monitor ID doesn't exist
  • Monitor belongs to different user
  • Webhook ID doesn't exist
  • API key ID doesn't exist

Solutions:

  • Verify resource ID is correct
  • Check resource belongs to authenticated user
  • Use GET /monitors to list valid monitor IDs

Example Response:

{
"error": "Monitor not found",
"code": "ERR_NOT_FOUND"
}

Rate Limiting (429)

ERR_RATE_LIMIT

HTTP Status: 429 Too Many Requests

Description: Rate limit exceeded for registration or login attempts.

Limits:

  • Registration: 3 attempts per hour per IP
  • Login: 5 attempts per 15 minutes per IP

Solutions:

  • Wait for rate limit window to reset
  • Use API keys for programmatic access (not rate limited)

Example Response:

{
"error": "Too many login attempts",
"code": "ERR_RATE_LIMIT",
"message": "Maximum 5 login attempts per 15 minutes"
}

ERR_LIMIT_EXCEEDED

HTTP Status: 429 Too Many Requests

Description: Account tier limit exceeded.

Free Tier Limits:

  • 10 monitors maximum
  • 100 API requests per day
  • 15 minute minimum check interval

Full Tier Limits:

  • Unlimited monitors
  • Unlimited API requests
  • 1 minute minimum check interval

Solutions:

  • Delete unused monitors
  • Upgrade to Full tier at need2.watch/pricing
  • Wait for daily API request counter to reset (midnight UTC)

Example Response:

{
"error": "Limit exceeded",
"code": "ERR_LIMIT_EXCEEDED",
"message": "Free tier: 10 monitors maximum. Upgrade at /pricing",
"upgradeUrl": "/pricing"
}

Server Errors (500)

ERR_INTERNAL

HTTP Status: 500 Internal Server Error

Description: Unexpected server error.

Common Causes:

  • Database connection failure
  • External API timeout (LLM, screenshot service)
  • Unexpected exception

Solutions:

  • Retry the request with exponential backoff
  • Check status.need2.watch for service status
  • Contact support if issue persists

Example Response:

{
"error": "Internal server error",
"code": "ERR_INTERNAL",
"message": "Database connection timeout"
}

Webhook-Specific Errors

ERR_WEBHOOK_DELIVERY_FAILED

HTTP Status: N/A (logged in delivery logs)

Description: Webhook delivery failed after all retries.

Common Causes:

  • Endpoint unreachable
  • Endpoint returned non-2xx status
  • Connection timeout (30s)
  • SSL certificate error

Solutions:

  • Verify endpoint is publicly accessible
  • Check endpoint returns 200 status
  • Ensure HTTPS certificate is valid
  • Respond within 30 seconds

Retry Schedule: 15s, 1m, 5m, 30m, 2h, 12h (6 attempts total)

ERR_WEBHOOK_SIGNATURE_INVALID

HTTP Status: 401 Unauthorized (from your endpoint)

Description: Webhook signature verification failed.

Common Causes:

  • Using parsed JSON instead of raw body
  • Incorrect secret
  • Not using HMAC-SHA256

Solutions:

// ✓ Correct: Use raw body
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-need2watch-signature'];
const valid = verifySignature(req.body, signature, secret);
// ...
});

// ✗ Wrong: Using parsed body
app.post('/webhook', express.json(), (req, res) => {
const signature = req.headers['x-need2watch-signature'];
const valid = verifySignature(req.body, signature, secret); // FAILS
// ...
});

Error Handling Best Practices

Retry with Exponential Backoff

async function callApiWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);

if (response.ok) {
return await response.json();
}

if (response.status === 429) {
// Rate limited - wait and retry
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}

if (response.status >= 500) {
// Server error - retry
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}

// Client error (4xx) - don't retry
const error = await response.json();
throw new Error(error.message || error.error);

} catch (err) {
if (attempt === maxRetries - 1) throw err;
}
}
}

Parse Error Responses

async function handleApiError(response) {
const error = await response.json();

switch (error.code) {
case 'ERR_UNAUTHORIZED':
// Refresh token or redirect to login
break;

case 'ERR_LIMIT_EXCEEDED':
// Show upgrade prompt
if (error.upgradeUrl) {
window.location.href = error.upgradeUrl;
}
break;

case 'ERR_RATE_LIMIT':
// Show user-friendly rate limit message
showToast('Too many requests. Please wait a moment.');
break;

case 'ERR_INVALID_REQUEST':
// Show validation errors to user
showValidationError(error.message);
break;

default:
// Generic error handling
console.error('API error:', error);
showToast('An error occurred. Please try again.');
}
}

Log Errors for Debugging

function logApiError(error, context) {
console.error('API Error', {
code: error.code,
message: error.message,
context,
timestamp: new Date().toISOString(),
userId: getCurrentUserId(),
endpoint: context.url,
method: context.method
});

// Send to error tracking service
if (error.code === 'ERR_INTERNAL') {
Sentry.captureException(new Error(error.message), {
tags: { errorCode: error.code },
extra: context
});
}
}

HTTP Status Code Summary

Status CodeError CodeDescription
400ERR_INVALID_REQUESTRequest validation failed
400ERR_INVALID_EMAILInvalid email format
400ERR_WEAK_PASSWORDPassword requirements not met
400ERR_EMAIL_EXISTSEmail already registered
401ERR_UNAUTHORIZEDAuthentication failed
401ERR_INVALID_REFRESH_TOKENRefresh token invalid/expired
404ERR_NOT_FOUNDResource not found
429ERR_RATE_LIMITToo many requests (temporary)
429ERR_LIMIT_EXCEEDEDAccount tier limit exceeded
500ERR_INTERNALInternal server error

Debugging Tips

Enable Request Logging

const response = await fetch(url, {
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});

console.log('Request:', {
url,
method: 'POST',
headers: { 'X-API-Key': apiKey.substring(0, 12) + '...' },
body: data
});

console.log('Response:', {
status: response.status,
statusText: response.statusText,
body: await response.json()
});

Check API Status

Before debugging, verify services are operational:

curl https://api.need2.watch/v1/health

Expected response:

{
"status": "ok",
"timestamp": 1706198400000,
"version": "0.1.0",
"checks": {
"database": true,
"kv": true,
"r2": true
}
}

If status: "degraded", check status.need2.watch for incidents.

Test with curl

Isolate issues by testing with curl:

# Test authentication
curl -v https://api.need2.watch/v1/monitors \
-H "X-API-Key: n2w_live_xxxxx"

# Check response headers
curl -I https://api.need2.watch/v1/health

# Test with invalid key
curl -v https://api.need2.watch/v1/monitors \
-H "X-API-Key: invalid"

Getting Help

If you encounter an error not documented here:

  1. Check status.need2.watch for service incidents
  2. Review API Reference for endpoint-specific requirements
  3. Search GitHub Issues
  4. Contact support: support@need2.watch

Include in your support request:

  • Error code and message
  • Request details (endpoint, method, payload)
  • Response headers
  • Timestamp
  • Account email