Common API Issues

🎉 New: API error responses now return proper JSON instead of HTML pages, making it easier to handle errors programmatically in your applications.

🔐 Authentication Problems

401 Unauthorized Error

Symptoms: API requests return "Unauthorized" error

Common Causes:

  • Invalid or expired API key
  • Missing Authorization header
  • Wrong API key format
  • Using test key in production

Solutions:

  • Verify API key is correct and active
  • Check Authorization header format: Bearer {api_key}
  • Ensure using live keys for production
  • Regenerate API keys if compromised

403 Forbidden Error

Symptoms: Valid authentication but access denied

Common Causes:

  • Insufficient permissions for API key
  • Resource not accessible for your market
  • Rate limit exceeded
  • IP address restrictions

Solutions:

  • Check API key permissions in admin panel
  • Verify market ID in requests
  • Implement rate limiting in your application
  • Contact support for IP whitelist updates

📡 Connection Issues

Network Timeouts

Symptoms: Requests hang or timeout

Common Causes:

  • Slow network connection
  • Large payload sizes
  • Server overload
  • Firewall blocking requests

Solutions:

  • Increase timeout values (max 30 seconds)
  • Implement retry logic with exponential backoff
  • Check firewall and proxy settings
  • Use pagination for large data sets

SSL/TLS Certificate Errors

Symptoms: Certificate verification failures

Common Causes:

  • Outdated certificate store
  • Corporate firewall interference
  • Self-signed certificates in development
  • Clock synchronization issues

Solutions:

  • Update system certificate store
  • Configure proxy settings correctly
  • Use proper certificates in all environments
  • Synchronize system clock

🔧 Error Response Handling

Improved Error Responses

What's Changed: API endpoints now consistently return JSON error responses

Error Response Format:

{
  "error": true,
  "message": "Human-readable error description",
  "code": "ERROR_CODE",
  "details": {
    // Additional context when available
  }
}

Benefits:

  • Consistent error format across all endpoints
  • Machine-readable error codes for automated handling
  • Helpful error messages for debugging
  • No more HTML error pages in API responses

Example Error Handling:

try {
  const response = await fetch('/api/orders', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`
			},
    body: JSON.stringify(orderData)
	});

  const data = await response.json();

  if (!response.ok) {
    // Handle API error
    console.error(`API Error: ${data.message} (${data.code})`);

    switch (data.code) {
      case 'INVALID_PAYMENT':
        handlePaymentError(data.details);
        break;
      case 'INSUFFICIENT_STOCK':
        handleStockError(data.details);
        break;
      default:
        showGenericError(data.message);
			}
		}
	} catch (error) {
  // Handle network or parsing errors
  console.error('Request failed:', error);
	}

Webhook Troubleshooting

Webhooks Not Being Delivered

Diagnostic Steps:

  1. Check webhook URL accessibility from external networks
  2. Verify endpoint returns 200 status code
  3. Test webhook URL with curl or Postman
  4. Review webhook logs in admin dashboard

Testing Webhook Endpoint

# Test webhook endpoint accessibility
curl -X POST https://your-app.com/webhooks/locallygrown \
  -H "Content-Type: application/json" \
  -H "X-LocallyGrown-Signature: test" \
  -d='{"test": true}'

# Expected response: 200 OK

# Check webhook logs
tail -f /var/log/your-app/webhooks.log

Signature Verification Failures

Common Problems:

  • Incorrect webhook secret
  • Wrong payload encoding
  • Modified request body
  • Timing-based signature mismatches

Debug Signature Verification

// Log signature components for debugging
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-locallygrown-signature'];
  const payload = JSON.stringify(req.body);

  console.log('Received signature:', signature);
  console.log('Payload length:', payload.length);
  console.log('Payload preview:', payload.substring(0, 100));

  // Your verification logic here
  const isValid = verifySignature(payload, signature, webhookSecret);
  console.log('Signature valid:', isValid);

  if (!isValid) {
    console.log('Expected signature would be:', generateSignature(payload, webhookSecret));
    return res.status(401).send('Invalid signature');
  }

  res.status(200).send('OK');
});

Duplicate Event Processing

Symptoms: Same event processed multiple times

Solutions:

  • Implement idempotency using event IDs
  • Use database constraints to prevent duplicates
  • Respond with 200 for already processed events
  • Implement proper error handling

Idempotency Implementation

const processedEvents = new Set();

app.post('/webhook', async (req, res) => {
  const { id, type, data } = req.body;

  // Check if event already processed
  if (processedEvents.has(id) || await isEventInDatabase(id)) {
    console.log(`Event ${id} already processed`);
    return res.status(200).send('Already processed');
  }

  try {
    await processEvent(type, data);
    await saveEventToDatabase(id, type, data);
    processedEvents.add(id);

    res.status(200).send('OK');
  } catch (error) {
    console.error(`Failed to process event ${id}:`, error);
    res.status(500).send('Processing failed');
  }
});

Payment Integration Issues

Payment Failures

Common Error Codes:

  • card_declined - Card issuer declined the payment
  • insufficient_funds - Not enough money in account
  • invalid_card - Card number or details invalid
  • expired_card - Card past expiration date

Debugging Steps:

  1. Check Stripe/payment processor logs
  2. Verify card details and test with known good card
  3. Test in sandbox mode first
  4. Review payment method configuration

Webhook Event Mismatches

Symptoms: Payment status in LocallyGrown doesn't match processor

Solutions:

  • Verify webhook endpoints are configured correctly
  • Check webhook event filtering
  • Implement webhook retry handling
  • Monitor webhook delivery logs

Integration Performance Issues

Rate Limiting Problems

429 Too Many Requests

Symptoms: API returns rate limit errors

Solutions:

  • Implement exponential backoff retry logic
  • Use batch operations where available
  • Cache frequently accessed data
  • Spread requests over time

Rate Limiting with Retry Logic

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

      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
        console.log(`Rate limited, retrying after ${retryAfter}s`);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      return response;
    } catch (error) {
      if (attempt === maxRetries) {
        throw error;
      }
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }
}

Slow Response Times

Performance Optimization

  • Use pagination - Request data in smaller chunks
  • Implement caching - Cache static or slow-changing data
  • Parallel requests - Make multiple API calls concurrently
  • Filter data - Request only needed fields and records

Parallel API Requests

// Instead of sequential requests
const orders = await getOrders();
const customers = await getCustomers();
const products = await getProducts();

// Use parallel requests
const [orders, customers, products] = await Promise.all([
  getOrders(),
  getCustomers(),
  getProducts()
]);

// With error handling
const results = await Promise.allSettled([
  getOrders(),
  getCustomers(),
  getProducts()
]);

results.forEach((result, index) => {
  if (result.status === 'rejected') {
    console.error(`Request ${index} failed:`, result.reason);
  }
});

Debugging Tools and Techniques

API Request Debugging

curl Commands

Test API endpoints directly:

# Test authentication
curl -H "Authorization: Bearer sk_test_..." \
     https://api.locallygrown.net/v1/orders

# Test with verbose output
curl -v -X POST \
     -H "Authorization: Bearer sk_test_..." \
     -H "Content-Type: application/json" \
     -d='{"test": "data"}' \
     https://api.locallygrown.net/v1/webhook-test

# Save response to file
curl -o response.json \
     -H "Authorization: Bearer sk_test_..." \
     https://api.locallygrown.net/v1/customers

Network Monitoring

Monitor API traffic and responses:

  • Browser DevTools - Network tab for web requests
  • Wireshark - Detailed network packet analysis
  • Charles Proxy - HTTP debugging proxy
  • Postman - API testing and debugging

Logging Best Practices

What to Log

  • Request details - Method, URL, headers (not auth tokens)
  • Response status - Status codes and error messages
  • Timing information - Request duration and timestamps
  • User context - User ID, market ID, session info

Structured Logging Example

const logger = require('winston');

// Configure structured logging
const apiLogger = logger.createLogger({
  format: logger.format.combine(
    logger.format.timestamp(),
    logger.format.json()
  ),
  transports: [
    new logger.transports.File({ filename: 'api.log' })
  ]
});

// Log API requests
function logApiRequest(req, res, responseTime) {
  apiLogger.info({
    type: 'api_request',
    method: req.method,
    url: req.url,
    statusCode: res.statusCode,
    responseTime: responseTime,
    userAgent: req.headers['user-agent'],
    userId: req.user?.id,
    marketId: req.headers['x-market-id']
  });
}

// Log errors with context
function logError(error, context) {
  apiLogger.error({
    type: 'error',
    message: error.message,
    stack: error.stack,
    context: context,
    timestamp: new Date().toISOString()
  });
}

Environment-Specific Issues

Development Environment

Common Issues:

  • Using production API keys in development
  • SSL certificate problems with localhost
  • CORS issues with browser-based requests
  • Environment variable configuration

Solutions:

  • Use test API keys for development
  • Configure local SSL or use tunneling tools (ngrok)
  • Set up proper CORS headers
  • Use .env files for configuration

Production Environment

Common Issues:

  • Environment variable mismatches
  • Network connectivity restrictions
  • Load balancer configuration problems
  • Database connection issues

Solutions:

  • Validate environment configuration on deployment
  • Configure firewall rules for API access
  • Ensure load balancer passes headers correctly
  • Implement connection pooling and health checks

Environment Configuration Check

// Validate environment configuration
function validateEnvironment() {
  const required = [
    'LOCALLYGROWN_API_KEY',
    'LOCALLYGROWN_WEBHOOK_SECRET',
    'DATABASE_URL',
    'REDIS_URL'
  ];

  const missing = required.filter(key => !process.env[key]);

  if (missing.length > 0) {
    console.error('Missing required environment variables:', missing);
    process.exit(1);
  }

  // Validate API key format
  const apiKey = process.env.LOCALLYGROWN_API_KEY;
  if (!apiKey.startsWith('sk_')) {
    console.error('Invalid API key format');
    process.exit(1);
  }

  console.log('Environment configuration validated');
}

validateEnvironment();

Error Monitoring and Alerting

Monitoring Setup

  • Error tracking - Use Sentry, Bugsnag, or similar services
  • API monitoring - Monitor endpoint availability and response times
  • Log aggregation - Centralize logs with ELK stack or similar
  • Metrics collection - Track business and technical metrics

Key Metrics to Monitor

API Health

  • Response time percentiles
  • Error rate by endpoint
  • Rate limit utilization
  • Authentication failures

Integration Health

  • Webhook delivery success rate
  • Data synchronization lag
  • Failed payment processing
  • Queue processing delays

Business Metrics

  • Order processing time
  • Customer signup rate
  • Revenue tracking accuracy
  • Inventory sync reliability
💡 Pro Tip: Set up proactive monitoring with alerts for critical failures. Don't wait for users to report issues - detect and resolve problems before they impact the business.

Getting Additional Help

Support Resources

  • Technical documentation - Complete API and integration guides
  • Developer support - Email support for integration questions
  • Community forums - Connect with other developers
  • Status page - Real-time system status and incident updates

When Contacting Support

Include these details for faster resolution:

  • Error messages - Complete error text and codes
  • Request details - API endpoint, method, payload (sanitized)
  • Response details - Status codes, headers, response body
  • Environment info - Development vs production, library versions
  • Steps to reproduce - Clear reproduction steps
  • Expected vs actual behavior - What should happen vs what happens

Support Request Template

Subject: API Integration Issue - [Brief Description]

Environment: Production/Development
API Endpoint: GET /v1/orders
Error Code: 429
Response Time: 2024-01-15 10:30:00 UTC

Error Message:
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests"
}

Request Details:
- Authorization: Bearer sk_live_xxx... (last 4 characters)
- Content-Type: application/json
- User-Agent: MyApp/1.0

Steps to Reproduce:
1. Make 100 API requests in quick succession
2. Error occurs on request #51

Expected Behavior:
Requests should be processed with appropriate rate limiting

Additional Context:
- This started happening after deploying version 2.1
- Same code works fine in development environment

Troubleshooting Checklist

Systematic troubleshooting saves time and leads to faster resolution. Follow the debugging process and don't hesitate to ask for help when needed.