All documentation

Error Handling

Error shapes, status codes, and retry guidance.

Error Handling

Error Response Format

All errors follow a consistent JSON structure:

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {
      "field": "Additional context"
    }
  }
}

HTTP Status Codes

Status CodeMeaningDescription
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestInvalid request parameters or body
401UnauthorizedMissing or invalid API key
403ForbiddenInsufficient permissions
404Not FoundResource not found
409ConflictResource conflict (varies by endpoint)
422Unprocessable EntityValidation errors
429Too Many RequestsRate limit or quota exceeded
500Internal Server ErrorServer error
503Service UnavailableService temporarily unavailable

Error Codes

Authentication Errors

UNAUTHORIZED (401)

Invalid or missing API key.

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or missing API key",
    "details": {}
  }
}

Resolution:

  • Verify the x-api-key header is present
  • Check the API key format is correct
  • Ensure the key has not been revoked

Validation Errors

VALIDATION_ERROR (400)

Request validation failed.

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "eventName": "eventName is required",
      "customer.email": "Invalid email format"
    }
  }
}

Resolution:

  • Review the details object for specific field errors
  • Ensure all required fields are present
  • Verify field formats match the API specification

UNPROCESSABLE_ENTITY (422)

Used when payload is structurally valid JSON but fails domain validation.

Common examples:

  • POST /api/v1/websdk/signals with sentAt outside the allowed +/-5 minute window
  • POST /api/v1/websdk/signals where sdkSessionId does not match the authenticated SDK token

Not Found Errors

NOT_FOUND (404)

Requested resource does not exist.

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Decision with ID evt_123 not found",
    "details": {}
  }
}

Resolution:

  • Verify the resource ID is correct
  • Check the resource belongs to your tenant
  • Ensure the resource has not been deleted

Rate Limiting Errors

QUOTA_EXCEEDED (429)

Quota limit reached.

{
  "error": {
    "code": "QUOTA_EXCEEDED",
    "message": "Quota exceeded",
    "details": {
      "limit": 10000,
      "window": "1 hour",
      "retryAfter": 3600
    }
  }
}

Resolution:

  • Wait for the quota window to reset
  • Upgrade your plan for higher limits
  • Implement request throttling in your application

See for details.

Conflict Errors

CONFLICT (409)

Resource conflict. Some endpoints may return 409 when a write cannot be applied due to a conflicting state.

{
  "error": {
    "code": "CONFLICT",
    "message": "Conflict",
    "details": {
      "reason": "example"
    }
  }
}

Resolution:

  • Inspect details for the specific conflict reason
  • Adjust the request or resolve the conflicting state, then retry

Server Errors

INTERNAL_SERVER_ERROR (500)

Unexpected server error.

{
  "error": {
    "code": "INTERNAL_SERVER_ERROR",
    "message": "An unexpected error occurred",
    "details": {
      "requestId": "req_abc123"
    }
  }
}

Resolution:

  • Retry the request after a short delay
  • If the error persists, contact support with the requestId

SERVICE_UNAVAILABLE (503)

Service temporarily unavailable.

{
  "error": {
    "code": "SERVICE_UNAVAILABLE",
    "message": "Service temporarily unavailable",
    "details": {
      "retryAfter": 60
    }
  }
}

Resolution:

  • Wait for the specified retryAfter seconds
  • Implement exponential backoff retry logic

Error Handling Best Practices

1. Always Check Status Codes

const response = await fetch(url, options);
if (!response.ok) {
  const error = await response.json();
  // Handle error based on error.code
}

2. Implement Retry Logic

async function makeRequestWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      if (response.ok) return response;
      
      const errorData = await response.json();
      
      // Don't retry client errors (4xx) - they won't succeed on retry
      if (response.status >= 400 && response.status < 500) {
        const error = new Error(errorData.message || 'Client error');
        error.status = response.status;
        error.data = errorData;
        throw error;
      }
      
      // Retry server errors (5xx) with exponential backoff
      if (response.status >= 500) {
        await sleep(Math.pow(2, i) * 1000);
        continue;
      }
    } catch (error) {
      // Don't retry client errors (4xx) - they won't succeed on retry
      if (error.status >= 400 && error.status < 500) {
        throw error;
      }
      
      // Only retry network errors (no status) and server errors (5xx)
      // Network errors don't have a status property, so they'll be retried
      if (i === maxRetries - 1) throw error;
      await sleep(Math.pow(2, i) * 1000);
    }
  }
}

3. Handle Rate Limits

async function handleRateLimit(response) {
  if (response.status === 429) {
    const error = await response.json();
    const retryAfter = error.error.details.retryAfter || 60;
    
    console.log(`Rate limited. Retrying after ${retryAfter} seconds`);
    await sleep(retryAfter * 1000);
    return true; // Indicate retry should happen
  }
  return false;
}

4. Log Errors for Debugging

async function logError(error, context) {
  console.error('API Error:', {
    code: error.error.code,
    message: error.error.message,
    details: error.error.details,
    context,
    timestamp: new Date().toISOString(),
  });
}

Troubleshooting

Common Issues

"Invalid API key"

  • Verify the key format: naiza_api_sk_live_<32-chars>
  • Check for extra spaces or newlines
  • Ensure the key hasn't been revoked

"Validation failed"

  • Review the API documentation for required fields
  • Check field types and formats
  • Ensure JSON is properly formatted

"sdkSessionId does not match token"

  • Ensure your backend mints the token and passes the same sdkSessionId to the browser
  • Do not reuse a token across unrelated browser sessions

"Quota exceeded"

  • Check your current usage in the dashboard
  • Wait for the quota window to reset
  • Consider upgrading your plan

"Service unavailable"

  • Check Naiza status page
  • Wait a few minutes and retry
  • Contact support if the issue persists

Getting Help

If you encounter errors not covered here:

  1. Check the for endpoint-specific errors
  2. Review your request format and parameters
  3. Contact support with:
    • Error code and message
    • Request details (sanitized)
    • Request ID (if available)
    • Timestamp of the error