Troubleshooting
This guide helps you diagnose and resolve common issues with API submissions.
Common Error Scenarios
Authentication Errors
401 Unauthorized
Symptoms: All API requests return 401 status
Possible Causes:
- Invalid or expired API token
- Missing Authorization header
- Incorrect token format
Solutions:
# Test your token
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://your-domain.com/api/test
# Check token format (should be 80 characters)
echo $API_TOKEN | wc -c
Verification Steps:
- Confirm API token is exactly 80 characters
- Check token hasn't expired (contact admin)
- Verify Authorization header format:
Bearer <token> - Ensure API user account is active
403 Forbidden
Symptoms: Authentication succeeds but access denied
Possible Causes:
- API user lacks workflow access permissions
- Workflow is disabled or archived
- IP address restrictions
Solutions:
- Contact admin to verify workflow permissions
- Check if workflow ID exists and is active
- Verify your IP is whitelisted (if restrictions apply)
Validation Errors
400 Bad Request - Field Validation
Error Response Example:
{
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"details": {
"field_errors": {
"email": "Invalid email format",
"start_date": "Date must be in future",
"amount": "Value must be greater than 0"
}
}
}
Debugging Steps:
- Check each field against form validation rules
- Verify data types match expected format
- Ensure required fields are present
- Validate date formats (ISO 8601: YYYY-MM-DD)
- Check numeric ranges and constraints
400 Bad Request - JSON Format
Symptoms: "Invalid JSON" error
Common Issues:
// ❌ Incorrect - trailing comma
{
"name": "John",
"age": 30,
}
// ❌ Incorrect - unescaped quotes
{
"description": "He said "hello""
}
// ✅ Correct
{
"name": "John",
"age": 30,
"description": "He said \"hello\""
}
Validation Tools:
- Use JSON validators (jsonlint.com)
- Test with curl or Postman first
- Enable JSON syntax checking in your IDE
Rate Limiting Issues
429 Too Many Requests
Error Response:
{
"error": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"limit_type": "hourly_per_ip",
"retry_after": 3600
}
Solutions:
- Implement Exponential Backoff:
import time
import random
def submit_with_retry(data, max_retries=3):
for attempt in range(max_retries):
try:
response = submit_data(data)
return response
except RateLimitError as e:
if attempt == max_retries - 1:
raise
# Exponential backoff with jitter
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
- Monitor Rate Limit Headers:
def check_rate_limits(response):
remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
if remaining < 10: # Low remaining requests
wait_time = reset_time - int(time.time())
print(f"Rate limit low. Waiting {wait_time} seconds...")
time.sleep(wait_time)
- Batch Operations:
# Instead of individual submissions
for item in items:
submit_single(item) # ❌ May hit rate limits
# Batch multiple items
batches = [items[i:i+10] for i in range(0, len(items), 10)]
for batch in batches:
submit_batch(batch) # ✅ More efficient
time.sleep(1) # Rate limiting delay
Workflow and Form Issues
404 Not Found - Workflow
Symptoms: "Workflow not found" error
Debugging:
- Verify workflow ID is correct
- Check if workflow is published (not draft)
- Confirm API user has access to workflow
- Ensure workflow hasn't been archived
Field Mapping Issues
Symptoms: Data not appearing correctly in submissions
Common Problems:
- Field Name Mismatch:
// Form has field "firstName" but API sends "first_name"
{
"first_name": "John" // ❌ Won't map
}
// Correct field name
{
"firstName": "John" // ✅ Will map
}
- Nested Component Issues:
// For nested components, use dot notation or nested objects
{
"address.street": "123 Main St", // Option 1
"address": { // Option 2
"street": "123 Main St",
"city": "Anytown"
}
}
- Array/Multi-value Fields:
// For checkboxes, select multiple, etc.
{
"skills": ["javascript", "python", "sql"], // ✅ Array format
"preferences": {
"email": true,
"sms": false,
"phone": true
}
}
Debugging Tools and Techniques
API Testing Tools
1. cURL Testing
# Basic submission test
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"test_field":"test_value"}' \
https://your-domain.com/api/submissions/workflow/123
# Verbose output for debugging
curl -v -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d @test_data.json \
https://your-domain.com/api/submissions/workflow/123
2. Postman Collection
Create a Postman collection with:
- Environment variables for API token and base URL
- Pre-request scripts for authentication
- Test scripts for response validation
// Pre-request script
pm.request.headers.add({
key: 'Authorization',
value: 'Bearer ' + pm.environment.get('api_token')
});
// Test script
pm.test("Status code is 201", function () {
pm.response.to.have.status(201);
});
pm.test("Response has submission ID", function () {
const jsonData = pm.response.json();
pm.expect(jsonData.submission.id).to.be.a('number');
});
Logging and Monitoring
Application Logging
import logging
import json
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('api_submissions.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger('api_submission')
def submit_with_logging(data):
logger.info(f"Submitting data: {json.dumps(data, indent=2)}")
try:
response = submit_data(data)
logger.info(f"Submission successful: {response['submission']['id']}")
return response
except Exception as e:
logger.error(f"Submission failed: {str(e)}")
logger.error(f"Request data: {json.dumps(data, indent=2)}")
raise
Response Analysis
def analyze_response(response):
"""Analyze API response for debugging"""
print(f"Status Code: {response.status_code}")
print(f"Headers: {dict(response.headers)}")
if response.status_code >= 400:
print(f"Error Response: {response.text}")
else:
data = response.json()
print(f"Success: Submission ID {data['submission']['id']}")
# Check rate limit headers
if 'X-RateLimit-Remaining' in response.headers:
remaining = response.headers['X-RateLimit-Remaining']
reset_time = response.headers.get('X-RateLimit-Reset', 'Unknown')
print(f"Rate Limit: {remaining} requests remaining, resets at {reset_time}")
Performance Debugging
Request Timing
import time
import requests
def timed_request(url, data, headers):
start_time = time.time()
try:
response = requests.post(url, json=data, headers=headers)
end_time = time.time()
duration = end_time - start_time
print(f"Request completed in {duration:.2f} seconds")
if duration > 5.0: # Slow request threshold
print("⚠️ Slow request detected")
print(f"Data size: {len(str(data))} characters")
return response
except requests.exceptions.Timeout:
print("❌ Request timed out")
raise
except requests.exceptions.ConnectionError:
print("❌ Connection error")
raise
Memory Usage Monitoring
import psutil
import os
def monitor_memory_usage():
process = psutil.Process(os.getpid())
memory_info = process.memory_info()
print(f"Memory usage: {memory_info.rss / 1024 / 1024:.2f} MB")
if memory_info.rss > 500 * 1024 * 1024: # 500MB threshold
print("⚠️ High memory usage detected")
Environment-Specific Issues
Development Environment
Common Issues:
- Self-signed SSL certificates
- Local network restrictions
- Development vs production API endpoints
Solutions:
# For development with self-signed certificates
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# Disable SSL warnings (development only!)
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# Make request with SSL verification disabled
response = requests.post(url, json=data, headers=headers, verify=False)
Production Environment
Monitoring Checklist:
- SSL certificate validity
- Network connectivity
- DNS resolution
- Firewall rules
- Load balancer health
- API server status
Health Check Script:
import requests
import sys
def health_check():
try:
# Test basic connectivity
response = requests.get(
'https://your-domain.com/api/health',
timeout=10
)
if response.status_code == 200:
print("✅ API server is healthy")
return True
else:
print(f"❌ API server returned {response.status_code}")
return False
except requests.exceptions.RequestException as e:
print(f"❌ Health check failed: {e}")
return False
if __name__ == "__main__":
if not health_check():
sys.exit(1)
Getting Help
Information to Gather
When reporting issues, include:
-
Request Details:
- Full API endpoint URL
- Request headers (excluding sensitive tokens)
- Request body (sanitized)
- HTTP method used
-
Response Information:
- HTTP status code
- Response headers
- Complete error message
- Response body
-
Environment Details:
- Programming language and version
- HTTP library and version
- Operating system
- Network environment (corporate, cloud, etc.)
-
Timing Information:
- When the issue started
- Frequency of occurrence
- Any recent changes
Support Channels
- Technical Documentation: Check this wiki first
- System Administrator: For account and permission issues
- Development Team: For integration and technical questions
- Help Desk: For general support requests
Self-Service Debugging
- Check System Status: Verify if there are known issues
- Review Recent Changes: Check if anything changed in your code
- Test with Simple Data: Use minimal test data to isolate issues
- Check Logs: Review application and server logs
- Verify Permissions: Confirm API user has necessary access
By following this troubleshooting guide, you should be able to resolve most common API submission issues quickly and efficiently.