Troubleshooting Guide

Solutions to common integration issues with Audit1 API

Troubleshooting Guide

Common issues and solutions when integrating with Audit1 Developer API.


🔍 Quick Diagnostics

Run This First

# Test your API key
curl -i -X POST https://api.audit1.info/api/v1/payroll/reports \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "employer_id": "TEST",
    "period_start": "2024-01-01",
    "period_end": "2024-03-31",
    "employees": [{
      "employee_id": "EE_001",
      "name": "Test",
      "classification_code": "8810",
      "hours_worked": 520,
      "gross_wages": 26000
    }],
    "payroll_data": {
      "total_payroll": 26000,
      "total_hours": 520,
      "officer_payroll": 0,
      "subcontractor_payments": 0
    }
  }'

Expected: HTTP/1.1 202 Accepted with JSON response


❌ Authentication Errors

Error: "Invalid API key format"

Symptom:

{
  "error": "Authentication Failed",
  "message": "Invalid API key format. Expected audit1_test_sk_* or audit1_live_sk_*"
}

Causes & Solutions:

  1. Wrong Prefix

    # ❌ Wrong
    Authorization: Bearer sk_test_abc123...
    
    # ✅ Correct
    Authorization: Bearer audit1_test_sk_abc123...
  2. Extra Spaces

    # ❌ Wrong (space after Bearer)
    Authorization: Bearer  audit1_test_sk_abc123...
    
    # ✅ Correct
    Authorization: Bearer audit1_test_sk_abc123...
  3. Missing "Bearer"

    # ❌ Wrong
    Authorization: audit1_test_sk_abc123...
    
    # ✅ Correct
    Authorization: Bearer audit1_test_sk_abc123...
  4. Truncated Key

    • Key should be ~50 characters long
    • Check you copied the entire key from Dashboard

Error: "Missing Authorization header"

Symptom:

{
  "error": "Authentication Failed",
  "message": "Missing Authorization header"
}

Solution:

// ❌ Wrong - missing header
fetch('https://api.audit1.info/api/v1/payroll/reports', {
  method: 'POST',
  body: JSON.stringify(data)
});

// ✅ Correct - include Authorization
fetch('https://api.audit1.info/api/v1/payroll/reports', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
});

Error: "API key not found"

Symptom:

{
  "error": "Authentication Failed",
  "message": "API key not found or inactive"
}

Troubleshooting:

  1. Verify key exists in your portal dashboard (API Keys section)
  2. Check key is marked as "Active"
  3. Ensure you're using the secret key, not the key ID
  4. Try creating a new key

Portal URLs:


❌ Validation Errors

Error: "Missing required fields"

Symptom:

{
  "error": "Validation Error",
  "message": "Missing required fields: employees",
  "details": {
    "required": ["employer_id", "period_start", "period_end", "employees", "payroll_data"]
  }
}

Solution:

// ✅ Complete payload with all required fields
const payload = {
  employer_id: "EMP_12345",           // Required
  period_start: "2024-01-01",         // Required (YYYY-MM-DD)
  period_end: "2024-03-31",           // Required (YYYY-MM-DD)
  employees: [                        // Required (min 1 employee)
    {
      employee_id: "EE_001",
      name: "John Smith",
      classification_code: "8810",
      hours_worked: 520,
      gross_wages: 26000
    }
  ],
  payroll_data: {                     // Required
    total_payroll: 26000,
    total_hours: 520,
    officer_payroll: 0,
    subcontractor_payments: 0
  }
};

Error: "Invalid date format"

Symptom:

{
  "error": "Validation Error",
  "message": "Invalid date format for period_start",
  "details": {
    "expected": "YYYY-MM-DD",
    "received": "01/15/2024"
  }
}

Solution:

// ❌ Wrong formats
"period_start": "01/15/2024"     // US format
"period_start": "15/01/2024"     // EU format
"period_start": "2024-1-15"      // Missing leading zeros

// ✅ Correct format
"period_start": "2024-01-15"     // YYYY-MM-DD

Error: "Employees array cannot be empty"

Symptom:

{
  "error": "Validation Error",
  "message": "Employees array cannot be empty"
}

Solution:

// ❌ Wrong - empty array
"employees": []

// ❌ Wrong - null
"employees": null

// ✅ Correct - at least 1 employee
"employees": [
  {
    "employee_id": "EE_001",
    "name": "John Smith",
    "classification_code": "8810",
    "hours_worked": 520,
    "gross_wages": 26000
  }
]

Error: "Invalid employee data"

Symptom:

{
  "error": "Validation Error",
  "message": "Invalid employee data",
  "details": {
    "employees[0].classification_code": "Required field missing",
    "employees[1].gross_wages": "Must be a positive number"
  }
}

Employee Required Fields:

// For payroll reports
{
  "employee_id": "required",
  "name": "required",
  "classification_code": "required",
  "hours_worked": "required (number)",
  "gross_wages": "required (number > 0)"
}

// For hire action
{
  "employee_id": "required",
  "action": "hire",
  "name": "required",
  "hire_date": "required (YYYY-MM-DD)",
  "classification_code": "required"
}

// For terminate action
{
  "employee_id": "required",
  "action": "terminate",
  "termination_date": "required (YYYY-MM-DD)"
}

❌ Rate Limiting

Error: "Rate limit exceeded"

Symptom:

{
  "error": "Rate Limit Exceeded",
  "message": "Too many requests. Please retry after 60 seconds.",
  "details": {
    "retry_after": 60,
    "limit": 100,
    "window": "1 minute"
  }
}

Solution - Exponential Backoff:

async function submitWithRetry(data, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await submitPayroll(data);
    } catch (error) {
      if (error.status === 429) {
        // Wait before retrying: 1s, 2s, 4s
        const delay = Math.pow(2, i) * 1000;
        console.log(`Rate limited. Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
  throw new Error('Max retries exceeded');
}

Solution - Batch Processing:

async function processBatch(reports, batchSize = 10) {
  for (let i = 0; i < reports.length; i += batchSize) {
    const batch = reports.slice(i, i + batchSize);
    
    // Process batch
    await Promise.all(batch.map(report => submitPayroll(report)));
    
    // Wait 1 second between batches
    if (i + batchSize < reports.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
}

❌ Connection Issues

Error: "ECONNREFUSED" or "Network Error"

Causes:

  1. Wrong URL

    # ❌ Wrong
    https://developer-api.audit1.com
    https://sandbox-api.audit1.info
    
    # ✅ Correct
    https://api.audit1.info/api/v1
  2. Firewall Blocking

    • Check corporate firewall
    • Verify outbound HTTPS is allowed
    • Test from different network
  3. DNS Issues

    # Test DNS resolution
    nslookup api.audit1.info
    
    # Test connectivity
    ping api.audit1.info

Error: "SSL Certificate Error"

Solution:

// ❌ Don't disable SSL verification in production!
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // NEVER DO THIS

// ✅ Update your CA certificates instead
npm install -g n
n latest

Timeout Errors

Solution:

// Increase timeout
const axios = require('axios');

const client = axios.create({
  baseURL: 'https://api.audit1.info/api/v1',
  timeout: 30000, // 30 seconds
  headers: {
    'Authorization': `Bearer ${apiKey}`
  }
});

// Handle timeouts
try {
  const response = await client.post('/payroll/reports', data);
} catch (error) {
  if (error.code === 'ECONNABORTED') {
    console.error('Request timed out');
    // Retry with longer timeout
  }
}

❌ Response Issues

Receiving HTML Instead of JSON

Symptom:

<!DOCTYPE html>
<html>
<head><title>404 Not Found</title></head>
...

Causes:

  1. Wrong Endpoint

    # ❌ Wrong
    POST /payroll-reports
    
    # ✅ Correct
    POST /payroll/reports
  2. Missing /api/v1 prefix

    # ❌ Wrong
    https://api.audit1.info/payroll/reports
    
    # ✅ Correct
    https://api.audit1.info/api/v1/payroll/reports

Unexpected Response Format

Solution:

// Always check response status
const response = await fetch(url, options);

if (!response.ok) {
  const error = await response.json();
  console.error('API Error:', error);
  throw new Error(error.message);
}

const data = await response.json();
console.log('Success:', data);

❌ Environment Issues

Using Wrong Environment

Symptoms:

  • Test data appearing in production
  • Production data in test environment
  • Unexpected report ID prefixes

Solution:

// Clearly separate environments
const config = {
  development: {
    apiKey: process.env.AUDIT1_TEST_KEY, // audit1_test_sk_*
    environment: 'sandbox'
  },
  production: {
    apiKey: process.env.AUDIT1_LIVE_KEY, // audit1_live_sk_*
    environment: 'production'
  }
};

// Select based on NODE_ENV
const env = process.env.NODE_ENV || 'development';
const apiKey = config[env].apiKey;

// Verify correct environment
console.log(`Using ${env} environment`);
console.log(`Key prefix: ${apiKey.substring(0, 16)}...`);

Can't Find Sandbox URL

Clarification:

There is NO separate sandbox URL. Use the same URL with different API keys:

# Sandbox (test data)
curl -H "Authorization: Bearer audit1_test_sk_..." \
  https://api.audit1.info/api/v1/payroll/reports

# Production (real data)
curl -H "Authorization: Bearer audit1_live_sk_..." \
  https://api.audit1.info/api/v1/payroll/reports

🔧 Debugging Tools

Enable Request Logging

// Axios interceptor
axios.interceptors.request.use(request => {
  console.log('Request:', {
    method: request.method,
    url: request.url,
    headers: request.headers,
    data: request.data
  });
  return request;
});

axios.interceptors.response.use(
  response => {
    console.log('Response:', {
      status: response.status,
      data: response.data
    });
    return response;
  },
  error => {
    console.error('Error:', {
      status: error.response?.status,
      data: error.response?.data
    });
    throw error;
  }
);

Test with cURL

# Verbose output
curl -v -X POST https://api.audit1.info/api/v1/payroll/reports \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json

# Save response
curl -X POST https://api.audit1.info/api/v1/payroll/reports \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json \
  -o response.json

# Check response headers
curl -i -X POST ...

Validate JSON Payload

# Use jq to validate
cat payload.json | jq .

# Minify JSON
cat payload.json | jq -c .

# Pretty print
cat payload.json | jq '.'

📊 Health Check

Verify API Status

  1. Check Status Page: status.audit1.com
  2. Test Endpoint: Make a simple request
  3. Check Logs: Review application logs for errors

Self-Diagnostic Checklist

API Configuration:
[ ] Correct base URL (https://api.audit1.info/api/v1)
[ ] Valid API key format (audit1_test_sk_* or audit1_live_sk_*)
[ ] Authorization header included
[ ] Content-Type: application/json

Request Format:
[ ] Valid JSON payload
[ ] All required fields present
[ ] Correct date format (YYYY-MM-DD)
[ ] Positive numbers for wages/hours
[ ] At least 1 employee in array

Network:
[ ] HTTPS enabled
[ ] No firewall blocking
[ ] SSL certificates valid
[ ] Timeout set appropriately (30s+)

Error Handling:
[ ] Retry logic implemented
[ ] Errors logged properly
[ ] Rate limiting handled
[ ] Timeouts handled

🆘 Still Stuck?

Before Contacting Support

  1. Run diagnostics from this guide
  2. Check logs for error details
  3. Test with cURL to isolate issue
  4. Verify API status at status.audit1.com

Contact Support

Include this information:

  • Request ID (from response headers: X-Request-ID)
  • Timestamp of the error
  • Full error message and response
  • API key prefix (first 16 chars only)
  • Environment (sandbox/production)
  • Sample request (with sensitive data removed)

📧 Email: [email protected]


📚 Related Resources