Skip to main content

Comprehensive Issue Resolution

Common Issues and Solutions

Authentication & Authorization Problems

Error Code: 401 UnauthorizedCommon API token authentication issues and solutions:
# Test your API token
curl -X GET "https://{subdomain}.nudj.cx/api/v2/integration/me" \
  -H "x-api-token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json"
Common Issues:
  • Missing subdomain: Ensure you’re using the correct subdomain in the URL
  • Invalid token format: API tokens should not include “Bearer ” prefix
  • Wrong header name: Use x-api-token or Authorization (without “Bearer ”)
  • Expired token: Generate a new token from the admin dashboard
  • Wrong environment: Verify you’re calling the correct environment (dev/staging/production)
Valid Header Formats:
// Option 1: x-api-token header
headers: {
  'x-api-token': 'your-api-token-here',
  'Content-Type': 'application/json'
}

// Option 2: Authorization header (no Bearer prefix)
headers: {
  'Authorization': 'your-api-token-here',
  'Content-Type': 'application/json'
}
Error Messages:
  • "Unauthorized" - Token missing or invalid format
  • "Organisation ID not found in API token" - Token doesn’t contain valid org data
  • "User ID not found in API token" - Token doesn’t contain valid user data
  • "Organisation not found" - Wrong subdomain or org doesn’t exist
Error: Organisation not foundSubdomain-related authentication problems:
# Verify correct subdomain format
# Wrong: https://api.nudj.cx/api/v2/...
# Correct: https://{your-org}.nudj.cx/api/v2/...

# Test subdomain resolution
curl -I https://{your-subdomain}.nudj.cx/api/v2/integration/me
Common Problems:
  • Missing subdomain: API calls must include your organization’s subdomain
  • Wrong subdomain: Verify subdomain matches your organization exactly
  • Environment mismatch: Ensure you’re using the right environment subdomain
    • Development: {subdomain}.devadmin.nudj.cx
    • Staging: {subdomain}.stgadmin.nudj.cx
    • Production: {subdomain}.nudj.cx
Debug Steps:
  1. Verify your subdomain in the admin dashboard
  2. Check API tokens are generated for the correct organization
  3. Test with curl first to isolate issues
  4. Ensure DNS resolution is working for your subdomain

API Error Responses

Understanding standard API error responses:
{
  "message": "Invalid input data",
  "code": "BAD_REQUEST",
  "issues": [
    {
      "message": "Required field 'name' is missing",
      "path": ["name"],
      "code": "invalid_type"
    }
  ]
}
Debugging API Errors:
// Error handling utility
function handleApiError(error) {
  const errorData = error.response?.data || error.data || {};
  
  console.error('API Error:', {
    status: error.response?.status,
    code: errorData.code,
    message: errorData.message,
    issues: errorData.issues,
    requestId: errorData.requestId
  });

  switch (errorData.code) {
    case 'BAD_REQUEST':
      return handleValidationError(errorData.issues);
    case 'UNAUTHORIZED':
      return handleAuthError();
    case 'FORBIDDEN':
      return handlePermissionError();
    case 'NOT_FOUND':
      return handleNotFoundError();
    case 'RATE_LIMIT_EXCEEDED':
      return handleRateLimitError(errorData.retryAfter);
    default:
      return handleGenericError(errorData.message);
  }
}
Handling input validation failures:
// Example validation error response
const validationError = {
  "message": "Invalid input data",
  "code": "BAD_REQUEST",
  "issues": [
    {
      "message": "String must contain at least 3 character(s)",
      "path": ["name"],
      "code": "too_small"
    },
    {
      "message": "Required",
      "path": ["description"],
      "code": "invalid_type"
    },
    {
      "message": "Invalid enum value. Expected 'draft' | 'live' | 'archived'",
      "path": ["status"],
      "code": "invalid_enum_value"
    }
  ]
};

// Process validation errors
function processValidationErrors(issues) {
  const fieldErrors = {};
  
  issues.forEach(issue => {
    const fieldPath = issue.path.join('.');
    fieldErrors[fieldPath] = issue.message;
  });
  
  return fieldErrors;
}
Common Validation Issues:
  • Required fields missing: Check all required parameters are included
  • Invalid data types: Ensure numbers are numbers, strings are strings
  • Enum values: Use exact values from API documentation
  • String length: Check minimum/maximum length requirements
  • Format validation: Verify email, URL, and date formats
API rate limit exceeded errors:
// Rate limit handling with exponential backoff
async function apiCallWithRetry(apiFunction, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await apiFunction();
    } catch (error) {
      if (error.response?.status === 429) {
        const retryAfter = error.response.data?.retryAfter || Math.pow(2, attempt);
        console.log(`Rate limited. Retrying in ${retryAfter} seconds...`);
        
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

// Usage
const result = await apiCallWithRetry(async () => {
  return fetch(`https://${subdomain}.nudj.cx/api/v2/integration/challenges`, {
    headers: { 'x-api-token': token }
  });
});
Rate Limits by API (subject to change): Check response headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) for current enforced values.
  • Integration API: ~100 requests per minute
  • Admin API: ~200 requests per minute
  • Analytics API: ~50 requests per minute
Best Practices:
  • Implement exponential backoff
  • Cache responses when appropriate
  • Use batch endpoints when available
  • Monitor rate limit headers

Challenge & Gamification Issues

Issues with challenge progress and completion:
// Debug challenge participation
async function debugChallengeParticipation(challengeId, userId) {
  const challenge = await fetch(`/api/v2/integration/challenges/${challengeId}`);
  const participations = await fetch(`/api/v2/integration/action-participations?challengeId=${challengeId}&userId=${userId}`);
  
  console.log('Challenge Debug:', {
    challengeStatus: challenge.status,
    userEligible: challenge.eligibilityRules,
    totalActions: challenge.actions?.length,
    userParticipations: participations.data?.length,
    requiredActions: challenge.requiredActionIds
  });
}
Common Issues:
  • Eligibility rules: User doesn’t meet challenge requirements
  • Challenge status: Challenge is not live or has expired
  • Action completion: Not all required actions completed
  • Timing issues: Actions completed outside challenge window
  • Community access: User not member of required community
Troubleshooting Steps:
  1. Verify challenge is live and within date range
  2. Check user meets all eligibility requirements
  3. Confirm all required actions are completed
  4. Review action participation timestamps
  5. Validate community membership status
Problems with submitting action participations:
// Submit action participation with error handling
async function submitActionParticipation(actionId, response) {
  try {
    const result = await fetch('/api/v2/integration/action-participations', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-token': token
      },
      body: JSON.stringify({
        actionId,
        response,
        metadata: {
          submittedAt: new Date().toISOString(),
          userAgent: navigator.userAgent
        }
      })
    });

    if (!result.ok) {
      const error = await result.json();
      console.error('Action participation failed:', error);
      throw new Error(error.message);
    }

    return await result.json();
  } catch (error) {
    console.error('Action participation error:', error);
    throw error;
  }
}
Common Issues:
  • Invalid response format: Response doesn’t match action requirements
  • Duplicate submissions: Action already completed by user
  • Action not found: Invalid actionId provided
  • Challenge not active: Associated challenge is not live
  • Authentication issues: User token invalid or expired
Action Types & Requirements:
  • Quiz: Requires selectedAnswerId or answers array
  • Prediction: Requires prediction value and optional confidence
  • Social: May require external verification
  • Video: Requires viewing time and progress data
  • Custom: Check specific action requirements
Problems with reward calculations:
// Debug points calculation
function debugPointsCalculation(actionParticipation) {
  console.log('Points Debug:', {
    basePoints: actionParticipation.pointsEarned,
    bonusPoints: actionParticipation.bonusPoints,
    xpEarned: actionParticipation.xpEarned,
    multipliers: actionParticipation.appliedMultipliers,
    streakBonus: actionParticipation.streakBonus
  });
}
Common Issues:
  • Delayed calculation: Points may take time to process
  • Multiplier errors: Community or user multipliers not applied
  • Streak interruption: Daily streak broken affecting bonuses
  • Event timing: Points calculated based on action completion time
  • Rounding errors: Floating point precision in calculations
Verification Steps:
  1. Check base points configuration for action
  2. Verify active multipliers and bonuses
  3. Confirm streak status and requirements
  4. Review event timestamps and timing rules
  5. Test with small point values to isolate issues

Reward & Commerce Issues

Problems redeeming rewards:
// Debug reward redemption
async function debugRewardRedemption(rewardId, userId) {
  const reward = await fetch(`/api/v2/integration/rewards/${rewardId}`);
  const userPoints = await fetch('/api/v2/integration/me');
  
  console.log('Redemption Debug:', {
    rewardCost: reward.cost,
    userPoints: userPoints.points,
    canAfford: userPoints.points >= reward.cost,
    rewardStatus: reward.status,
    availability: reward.availability,
    userEligible: reward.eligibilityRules
  });
}
Common Redemption Issues:
  • Insufficient points: User doesn’t have enough points
  • Reward unavailable: Reward is sold out or expired
  • Eligibility requirements: User doesn’t meet reward criteria
  • Geographic restrictions: Reward not available in user’s region
  • Stock limitations: Reward has limited quantity available
Error Responses:
{
  "message": "Insufficient points for redemption",
  "code": "INSUFFICIENT_POINTS",
  "required": 1000,
  "available": 750
}
Troubleshooting:
  1. Check user’s current point balance
  2. Verify reward is active and in stock
  3. Confirm user meets eligibility requirements
  4. Review geographic and temporal restrictions
  5. Test redemption flow with admin privileges
Problems with reward entries and giveaways:
// Check reward entry status
async function checkRewardEntries(userId) {
  const entries = await fetch('/api/v2/integration/me/reward-entries');
  
  entries.data.forEach(entry => {
    console.log('Entry Debug:', {
      rewardId: entry.rewardId,
      status: entry.status,
      drawDate: entry.drawDate,
      isProcessed: entry.isProcessed,
      winner: entry.isWinner
    });
  });
}
Common Issues:
  • Entry not recorded: Purchase/entry not properly recorded
  • Draw delays: Automatic draws not processing on time
  • Winner notification: Users not receiving winner notifications
  • Fulfillment delays: Physical rewards not being shipped
  • Status updates: Entry status not updating properly
Resolution Steps:
  1. Verify entry was recorded in system
  2. Check draw configuration and timing
  3. Review winner selection algorithm
  4. Confirm notification system is working
  5. Validate fulfillment partner integration

Integration & Performance Issues

Slow API responses and timeouts:
// Performance monitoring
async function monitorApiPerformance(endpoint) {
  const start = Date.now();
  
  try {
    const response = await fetch(endpoint, {
      headers: { 'x-api-token': token }
    });
    
    const duration = Date.now() - start;
    
    console.log('API Performance:', {
      endpoint,
      duration: `${duration}ms`,
      status: response.status,
      size: response.headers.get('content-length')
    });
    
    if (duration > 5000) {
      console.warn('Slow API response detected');
    }
    
    return response;
  } catch (error) {
    console.error('API Error:', {
      endpoint,
      duration: Date.now() - start,
      error: error.message
    });
    throw error;
  }
}
Performance Optimization:
  • Use pagination: Limit large data sets with limit and skip
  • Implement caching: Cache frequently accessed data
  • Optimize queries: Use specific field selection where available
  • Batch requests: Combine multiple operations when possible
  • Monitor response times: Set up alerts for slow responses
Timeout Settings:
// Configure appropriate timeouts
const apiClient = axios.create({
  baseURL: `https://${subdomain}.nudj.cx/api/v2`,
  timeout: 30000, // 30 second timeout
  headers: {
    'x-api-token': token,
    'Content-Type': 'application/json'
  }
});
Problems with data consistency:
// Data sync verification
async function verifyDataSync(entityType, entityId) {
  const cacheData = getFromCache(entityType, entityId);
  const apiData = await fetchFromApi(entityType, entityId);
  
  const isSync = JSON.stringify(cacheData) === JSON.stringify(apiData);
  
  if (!isSync) {
    console.warn('Data sync issue detected:', {
      entityType,
      entityId,
      cacheData,
      apiData,
      differences: findDifferences(cacheData, apiData)
    });
    
    // Force cache refresh
    refreshCache(entityType, entityId, apiData);
  }
  
  return apiData;
}
Common Sync Issues:
  • Cache staleness: Cached data not updating properly
  • Race conditions: Concurrent updates causing conflicts
  • Event processing delays: Events not processed in order
  • Database replication lag: Read replicas behind master
  • Client state management: Frontend state out of sync
Best Practices:
  • Implement proper cache invalidation
  • Use optimistic updates with rollback
  • Handle race conditions gracefully
  • Set appropriate cache TTL values
  • Use real-time updates where needed
Issues with external service integrations:
// Debug third-party integrations
async function debugThirdPartyIntegration(service) {
  try {
    const config = await fetch('/api/v2/integration/third-party-config');
    const serviceConfig = config[service];
    
    console.log('Integration Debug:', {
      service,
      enabled: serviceConfig?.enabled,
      configured: !!serviceConfig?.credentials,
      lastSync: serviceConfig?.lastSyncAt,
      errors: serviceConfig?.lastErrors
    });
    
    // Test connectivity
    if (serviceConfig?.enabled) {
      await testServiceConnection(service, serviceConfig);
    }
    
  } catch (error) {
    console.error(`${service} integration error:`, error);
  }
}
Common Integration Issues:
  • OAuth token expiry: Social media tokens need refresh
  • API changes: Third-party APIs change breaking integration
  • Rate limiting: External service rate limits exceeded
  • Authentication failures: Invalid or expired credentials
  • Service outages: Third-party service temporarily unavailable
Supported Integrations:
  • YouTube: Channel data, video interactions
  • Instagram: Profile data, post engagement
  • Spotify: Listening data, playlist interactions
  • Google: Authentication, profile data
  • Custom webhooks: Bidirectional data sync

Debugging Tools and Techniques

API Testing & Inspection

# Set environment variables to avoid exposing tokens
export NUDJ_SUBDOMAIN="your-subdomain"
export NUDJ_TOKEN="your-token"

# Test API endpoints with curl
curl -X GET "https://${NUDJ_SUBDOMAIN}.nudj.cx/api/v2/integration/me" \
  -H "x-api-token: ${NUDJ_TOKEN}" \
  -H "Content-Type: application/json" \
  -v # Verbose output for debugging

# Test with different headers
curl -X GET "https://${NUDJ_SUBDOMAIN}.nudj.cx/api/v2/integration/challenges" \
  -H "x-api-token: ${NUDJ_TOKEN}" \
  -H "x-language: en" \
  -H "Content-Type: application/json"

# Test POST requests
curl -X POST "https://${NUDJ_SUBDOMAIN}.nudj.cx/api/v2/integration/action-participations" \
  -H "x-api-token: ${NUDJ_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "actionId": "action_123",
    "response": {"answer": "test"}
  }'

# Note: Never paste live tokens directly. Use environment variables and rotate tokens regularly.

Log Analysis

// Enable detailed logging in browser
localStorage.setItem('nudj-debug', 'true');
localStorage.setItem('nudj-api-debug', 'true');

// Monitor network requests
function monitorApiCalls() {
  const originalFetch = window.fetch;
  
  window.fetch = async function(...args) {
    const [url, options] = args;
    const urlString = typeof url === 'string' ? url : url.toString();
    
    if (urlString.includes('nudj.cx')) {
      console.group('🌐 API Call');
      console.log('URL:', urlString);
      console.log('Options:', options);
      
      const start = performance.now();
      const response = await originalFetch.apply(this, args);
      const duration = performance.now() - start;
      
      console.log(`⏱️ Duration: ${duration.toFixed(2)}ms`);
      console.log('Status:', response.status);
      console.groupEnd();
      
      // Clone response to read body without consuming it
      const responseClone = response.clone();
      try {
        const data = await responseClone.json();
        console.log('Response Data:', data);
      } catch (e) {
        console.log('Response not JSON');
      }
      
      return response;
    }
    
    // For non-nudj URLs, just call original fetch
    return originalFetch.apply(this, args);
  };
}

monitorApiCalls();

Error Recovery Strategies

Retry Logic Implementation

class ApiRetryClient {
  constructor(baseUrl, token, maxRetries = 3) {
    this.baseUrl = baseUrl;
    this.token = token;
    this.maxRetries = maxRetries;
  }

  async request(endpoint, options = {}, retryCount = 0) {
    try {
      const response = await fetch(`${this.baseUrl}${endpoint}`, {
        ...options,
        headers: {
          'x-api-token': this.token,
          'Content-Type': 'application/json',
          ...options.headers
        }
      });

      // Don't retry client errors (4xx) except 401, 408, 429
      const retryableStatuses = [401, 408, 429, 500, 502, 503, 504];
      
      if (!response.ok && !retryableStatuses.includes(response.status)) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      if (!response.ok && retryCount < this.maxRetries) {
        const delay = this.calculateBackoffDelay(retryCount, response.status);
        console.log(`Retrying request in ${delay}ms (attempt ${retryCount + 1}/${this.maxRetries})`);
        
        await new Promise(resolve => setTimeout(resolve, delay));
        return this.request(endpoint, options, retryCount + 1);
      }

      return response;
    } catch (error) {
      if (retryCount < this.maxRetries) {
        const delay = this.calculateBackoffDelay(retryCount);
        console.log(`Retrying failed request in ${delay}ms (attempt ${retryCount + 1}/${this.maxRetries})`);
        
        await new Promise(resolve => setTimeout(resolve, delay));
        return this.request(endpoint, options, retryCount + 1);
      }
      
      throw error;
    }
  }

  calculateBackoffDelay(retryCount, statusCode = null) {
    // Special handling for rate limits
    if (statusCode === 429) {
      return Math.min(60000, 1000 * Math.pow(2, retryCount)); // Max 1 minute
    }
    
    // Exponential backoff with jitter
    const baseDelay = 1000 * Math.pow(2, retryCount);
    const jitter = Math.random() * 1000;
    return Math.min(10000, baseDelay + jitter); // Max 10 seconds
  }
}

// Usage
const apiClient = new ApiRetryClient('https://yourorg.nudj.cx/api/v2', 'your-token');
const response = await apiClient.request('/integration/challenges');

Graceful Error Handling

class ErrorHandler {
  static getErrorMessage(error, context = 'general') {
    const errorCode = error.response?.data?.code || error.code;
    const statusCode = error.response?.status || error.status;
    
    // Context-specific error messages
    const errorMessages = {
      authentication: {
        401: 'Please sign in to continue',
        403: 'You don\'t have permission to perform this action',
        'UNAUTHORIZED': 'Your session has expired. Please sign in again.'
      },
      challenge: {
        404: 'This challenge is no longer available',
        'CHALLENGE_EXPIRED': 'This challenge has ended',
        'ALREADY_COMPLETED': 'You\'ve already completed this challenge',
        'NOT_ELIGIBLE': 'You\'re not eligible for this challenge'
      },
      reward: {
        'INSUFFICIENT_POINTS': 'You don\'t have enough points for this reward',
        'OUT_OF_STOCK': 'This reward is currently out of stock',
        'GEOGRAPHIC_RESTRICTION': 'This reward is not available in your region'
      },
      general: {
        400: 'Please check your input and try again',
        404: 'The requested item was not found',
        429: 'Too many requests. Please wait a moment and try again',
        500: 'Something went wrong on our end. Please try again later',
        'NETWORK_ERROR': 'Please check your internet connection',
        'TIMEOUT': 'The request took too long. Please try again'
      }
    };

    const contextMessages = errorMessages[context] || {};
    const fallbackMessages = errorMessages.general;
    
    return (
      contextMessages[errorCode] ||
      contextMessages[statusCode] ||
      fallbackMessages[errorCode] ||
      fallbackMessages[statusCode] ||
      error.message ||
      'An unexpected error occurred'
    );
  }

  static handleApiError(error, context = 'general') {
    const message = this.getErrorMessage(error, context);
    
    // Log detailed error for developers
    console.error('API Error:', {
      context,
      status: error.response?.status,
      code: error.response?.data?.code,
      message: error.response?.data?.message,
      originalError: error
    });

    // Show user-friendly message
    this.showToast(message, 'error');
    
    // Handle specific error types
    if (error.response?.status === 401) {
      this.redirectToLogin();
    }
    
    return { userMessage: message, error };
  }

  static showToast(message, type = 'info') {
    // Implement your toast notification system
    console.log(`Toast [${type}]: ${message}`);
  }

  static redirectToLogin() {
    // Implement redirect to login
    window.location.href = '/auth/signin';
  }
}

// Usage in components
try {
  await submitChallenge(challengeId, response);
} catch (error) {
  ErrorHandler.handleApiError(error, 'challenge');
}

Performance Monitoring

API Response Time Tracking

class ApiPerformanceMonitor {
  constructor() {
    this.metrics = {
      requests: 0,
      totalTime: 0,
      errors: 0,
      slowRequests: 0,
      endpoints: new Map()
    };
    this.slowRequestThreshold = 3000; // 3 seconds
  }

  async trackRequest(endpoint, requestFunction) {
    const startTime = performance.now();
    const requestId = this.generateRequestId();
    
    try {
      console.log(`📊 [${requestId}] Starting request to ${endpoint}`);
      
      const result = await requestFunction();
      const duration = performance.now() - startTime;
      
      this.recordSuccess(endpoint, duration);
      
      if (duration > this.slowRequestThreshold) {
        console.warn(`🐌 [${requestId}] Slow request: ${endpoint} took ${duration.toFixed(2)}ms`);
      } else {
        console.log(`✅ [${requestId}] Request completed: ${endpoint} (${duration.toFixed(2)}ms)`);
      }
      
      return result;
    } catch (error) {
      const duration = performance.now() - startTime;
      this.recordError(endpoint, duration);
      
      console.error(`❌ [${requestId}] Request failed: ${endpoint} (${duration.toFixed(2)}ms)`, error);
      throw error;
    }
  }

  recordSuccess(endpoint, duration) {
    this.metrics.requests++;
    this.metrics.totalTime += duration;
    
    if (duration > this.slowRequestThreshold) {
      this.metrics.slowRequests++;
    }
    
    this.updateEndpointMetrics(endpoint, duration, true);
  }

  recordError(endpoint, duration) {
    this.metrics.requests++;
    this.metrics.errors++;
    this.metrics.totalTime += duration;
    
    this.updateEndpointMetrics(endpoint, duration, false);
  }

  updateEndpointMetrics(endpoint, duration, success) {
    if (!this.metrics.endpoints.has(endpoint)) {
      this.metrics.endpoints.set(endpoint, {
        requests: 0,
        totalTime: 0,
        errors: 0,
        avgTime: 0
      });
    }
    
    const endpointMetrics = this.metrics.endpoints.get(endpoint);
    endpointMetrics.requests++;
    endpointMetrics.totalTime += duration;
    
    if (!success) {
      endpointMetrics.errors++;
    }
    
    endpointMetrics.avgTime = endpointMetrics.totalTime / endpointMetrics.requests;
  }

  getReport() {
    const avgResponseTime = this.metrics.totalTime / this.metrics.requests;
    const errorRate = (this.metrics.errors / this.metrics.requests) * 100;
    const slowRequestRate = (this.metrics.slowRequests / this.metrics.requests) * 100;
    
    return {
      summary: {
        totalRequests: this.metrics.requests,
        avgResponseTime: avgResponseTime.toFixed(2) + 'ms',
        errorRate: errorRate.toFixed(2) + '%',
        slowRequestRate: slowRequestRate.toFixed(2) + '%'
      },
      endpoints: Array.from(this.metrics.endpoints.entries()).map(([endpoint, metrics]) => ({
        endpoint,
        requests: metrics.requests,
        avgTime: metrics.avgTime.toFixed(2) + 'ms',
        errorRate: ((metrics.errors / metrics.requests) * 100).toFixed(2) + '%'
      })).sort((a, b) => parseFloat(b.avgTime) - parseFloat(a.avgTime))
    };
  }

  generateRequestId() {
    return Math.random().toString(36).substr(2, 9);
  }

  // Method to be called periodically
  logReport() {
    const report = this.getReport();
    console.log('📈 API Performance Report:', report);
  }
}

// Usage
const monitor = new ApiPerformanceMonitor();

// Wrap API calls
const result = await monitor.trackRequest('/integration/challenges', async () => {
  return fetch('/api/v2/integration/challenges', {
    headers: { 'x-api-token': token }
  });
});

// Log periodic reports
setInterval(() => monitor.logReport(), 60000); // Every minute

Getting Help & Support

Before Contacting Support

1

Check System Status

Visit status.nudj.cx to check for known issues or ongoing maintenance.
2

Review Documentation

Check the relevant API documentation and examples for your use case.
3

Test with curl

Isolate the issue by testing API endpoints directly with curl or Postman.
4

Gather Debug Information

Collect error messages, request/response data, and system information.

Support Channels

Information to Include When Reporting Issues

When contacting support, please provide:
  • Organization subdomain
  • API endpoint being called
  • Environment (development/staging/production)
  • Timestamp of the issue
  • Browser/client information if applicable
  • Complete error message and stack trace
  • HTTP status codes and response bodies
  • Request payload and headers (remove sensitive data)
  • Steps to reproduce the issue
// Include this debug info in your report
const debugInfo = {
  timestamp: new Date().toISOString(),
  userAgent: navigator?.userAgent,
  apiEndpoint: 'specific endpoint called',
  requestId: 'if available from error response',
  organizationId: 'your org id',
  userId: 'affected user id (if applicable)'
};

Self-Service Debug Checklist

1

Verify Authentication

  • API token is valid and not expired
  • Correct subdomain in API URLs
  • Proper header format (x-api-token or Authorization)
  • Token has required permissions for endpoint
2

Check Request Format

  • URL structure matches API documentation
  • Request method (GET/POST/PUT/DELETE) is correct
  • Content-Type header is set to application/json
  • Request body is valid JSON (for POST/PUT requests)
  • All required parameters are included
3

Test Network Connectivity

  • Can reach the API subdomain (ping test)
  • No firewall blocking HTTPS traffic
  • DNS resolution working correctly
  • SSL certificate is valid
4

Review Response Handling

  • Parsing JSON responses correctly
  • Handling error responses appropriately
  • Checking HTTP status codes
  • Following pagination for large data sets
5

Monitor Rate Limits

  • Not exceeding API rate limits
  • Implementing retry logic with backoff
  • Caching responses where appropriate
  • Using batch endpoints when available

Quick Reference

Common Error Codes

CodeDescriptionCommon CausesSolutions
400Bad RequestInvalid input, missing required fieldsCheck request format and required parameters
401UnauthorizedInvalid/missing API tokenVerify token and authentication headers
403ForbiddenInsufficient permissionsCheck user roles and API permissions
404Not FoundResource doesn’t existVerify IDs and endpoint URLs
429Rate LimitedToo many requestsImplement backoff and retry logic
500Server ErrorInternal platform issueCheck status page, retry with backoff

API Rate Limits

Note: Rate limits are subject to change. Always check response headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) for current enforced values.
APIRequests per Minute (Approximate)Burst Limit (Approximate)
Integration API100200
Admin API200400
Analytics API50100

Debug Mode Activation

// Enable debug logging
localStorage.setItem('nudj-debug', 'true');
localStorage.setItem('nudj-api-debug', 'true');
localStorage.setItem('nudj-verbose', 'true');

// View stored debug info
console.log('Debug Settings:', {
  debug: localStorage.getItem('nudj-debug'),
  apiDebug: localStorage.getItem('nudj-api-debug'),
  verbose: localStorage.getItem('nudj-verbose')
});
Still experiencing issues? Don’t hesitate to reach out to our support team at support@nudj.cx with the debug information above.
I