Technical Troubleshooting
Diagnose and resolve technical issues with LocallyGrown integrations, APIs, webhooks, and applications. Find solutions to common problems and learn debugging techniques.
Common API Issues
🔐 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:
- Check webhook URL accessibility from external networks
- Verify endpoint returns 200 status code
- Test webhook URL with curl or Postman
- 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:
- Check Stripe/payment processor logs
- Verify card details and test with known good card
- Test in sandbox mode first
- 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
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