Error Handling
Understanding and handling API errors effectively for robust integrations.
Error Response Format
All API errors follow a consistent JSON format:
{
"error": {
"type": "VALIDATION_ERROR",
"message": "The linkedin_url field is required",
"code": "E1001",
"details": {
"field": "linkedin_url",
"value": null,
"constraint": "required"
},
"request_id": "req_2Xk9Lm3Np",
"timestamp": "2025-01-20T14:30:00Z"
}
}
Error Object Fields
Field | Type | Description |
---|---|---|
type |
string | Error category for programmatic handling |
message |
string | Human-readable error description |
code |
string | Specific error code for detailed handling |
details |
object | Additional context about the error |
request_id |
string | Unique identifier for request tracing |
HTTP Status Codes
Sales Webhooks uses standard HTTP status codes to indicate success or failure:
Success Codes
Code | Meaning | Usage |
---|---|---|
200 OK |
Request succeeded | GET, PUT, DELETE requests |
201 Created |
Resource created | POST requests |
204 No Content |
Success with no response body | DELETE requests |
Client Error Codes
Code | Meaning | Common Causes |
---|---|---|
400 Bad Request |
Invalid request | Malformed JSON, missing fields |
401 Unauthorized |
Authentication failed | Invalid or missing API key |
403 Forbidden |
Access denied | Insufficient permissions |
404 Not Found |
Resource not found | Invalid ID or deleted resource |
409 Conflict |
Resource conflict | Duplicate subscription |
422 Unprocessable Entity |
Validation failed | Invalid field values |
429 Too Many Requests |
Rate limit exceeded | Too many API calls |
Server Error Codes
Code | Meaning | Action |
---|---|---|
500 Internal Server Error |
Server error | Retry with backoff |
502 Bad Gateway |
Upstream error | Retry with backoff |
503 Service Unavailable |
Temporary outage | Retry after delay |
504 Gateway Timeout |
Request timeout | Retry with smaller batch |
Error Types Reference
Common error types and how to handle them:
Authentication Errors
AUTHENTICATION_FAILED
{
"error": {
"type": "AUTHENTICATION_FAILED",
"message": "Invalid API key",
"code": "E1101",
"details": {
"hint": "Check that your API key is correct and active"
}
}
}
How to handle:
- Verify API key is correct
- Check key hasn't been revoked
- Ensure using correct environment (live vs test)
Validation Errors
VALIDATION_ERROR
{
"error": {
"type": "VALIDATION_ERROR",
"message": "Invalid LinkedIn URL format",
"code": "E1201",
"details": {
"field": "linkedin_url",
"value": "not-a-url",
"constraint": "url_format",
"expected": "https://linkedin.com/in/username"
}
}
}
How to handle:
- Check field requirements in API docs
- Validate input before sending
- Use details object to identify specific issue
Rate Limit Errors
RATE_LIMIT_EXCEEDED
{
"error": {
"type": "RATE_LIMIT_EXCEEDED",
"message": "API rate limit exceeded",
"code": "E1301",
"details": {
"limit": 50,
"remaining": 0,
"reset_at": "2025-01-20T15:00:00Z",
"retry_after": 234
}
}
}
How to handle:
- Check
retry_after
seconds - Implement exponential backoff
- Use
X-RateLimit-*
headers proactively
Resource Errors
RESOURCE_NOT_FOUND
{
"error": {
"type": "RESOURCE_NOT_FOUND",
"message": "Subscription not found",
"code": "E1401",
"details": {
"resource": "subscription",
"id": "sub_9Yx7Kj2Mn"
}
}
}
How to handle:
- Verify resource ID is correct
- Check if resource was deleted
- Ensure resource belongs to your account
Handling Errors in Code
JavaScript/Node.js
async function createSubscription(linkedinUrl) {
try {
const subscription = await client.subscriptions.create({
entity_type: 'contact',
linkedin_url: linkedinUrl
});
return subscription;
} catch (error) {
// Check if it's an API error
if (error.response) {
const apiError = error.response.data.error;
switch (apiError.type) {
case 'VALIDATION_ERROR':
console.error(`Invalid data: ${apiError.message}`);
// Show validation error to user
break;
case 'RATE_LIMIT_EXCEEDED':
const retryAfter = apiError.details.retry_after;
console.log(`Rate limited. Retrying in ${retryAfter}s`);
await sleep(retryAfter * 1000);
return createSubscription(linkedinUrl); // Retry
case 'DUPLICATE_RESOURCE':
console.log('Subscription already exists');
// Handle duplicate gracefully
break;
default:
console.error(`API Error: ${apiError.message}`);
throw error;
}
} else {
// Network or other error
console.error('Network error:', error.message);
throw error;
}
}
}
Python
from saleswebhooks import SalesWebhooks, APIError
import time
def create_subscription_with_retry(client, linkedin_url, max_retries=3):
"""Create subscription with automatic retry on rate limits"""
for attempt in range(max_retries):
try:
subscription = client.subscriptions.create(
entity_type='contact',
linkedin_url=linkedin_url
)
return subscription
except APIError as e:
if e.error_type == 'RATE_LIMIT_EXCEEDED':
retry_after = e.details.get('retry_after', 60)
print(f"Rate limited. Waiting {retry_after}s...")
time.sleep(retry_after)
continue
elif e.error_type == 'VALIDATION_ERROR':
print(f"Validation error: {e.message}")
print(f"Field: {e.details.get('field')}")
raise
elif e.error_type == 'DUPLICATE_RESOURCE':
print("Subscription already exists")
return None
else:
print(f"API Error: {e.message}")
raise
except Exception as e:
print(f"Unexpected error: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt) # Exponential backoff
else:
raise
Error Recovery Strategies
💡 Best Practices
- • Implement retry logic - Use exponential backoff for transient errors
- • Log request IDs - Include in support tickets for faster resolution
- • Handle specific errors - Don't treat all errors the same
- • Validate inputs - Catch errors before making API calls
- • Monitor error rates - Track patterns to identify issues
Common Error Scenarios
Webhook Delivery Failures
{
"error": {
"type": "WEBHOOK_DELIVERY_FAILED",
"message": "Failed to deliver webhook after 4 attempts",
"code": "E1501",
"details": {
"webhook_id": "whd_3Zk1No5Pr",
"endpoint_url": "https://your-app.com/webhook",
"last_error": "Connection timeout",
"attempts": 4,
"first_attempt": "2025-01-20T14:00:00Z",
"last_attempt": "2025-01-20T14:00:36Z"
}
}
}
Subscription Limits
{
"error": {
"type": "LIMIT_EXCEEDED",
"message": "Subscription limit reached for your plan",
"code": "E1601",
"details": {
"limit": 1000,
"current": 1000,
"plan": "professional",
"upgrade_url": "https://console.saleswebhooks.com/billing/upgrade"
}
}
}
LinkedIn Data Errors
{
"error": {
"type": "LINKEDIN_ERROR",
"message": "LinkedIn profile is private or doesn't exist",
"code": "E1701",
"details": {
"linkedin_url": "https://linkedin.com/in/private-user",
"reason": "profile_private",
"suggestion": "Ensure the profile is public and URL is correct"
}
}
}
Troubleshooting Guide
🔍 Debug Checklist
- 1. Check the exact error message and type
- 2. Note the request ID for support
- 3. Verify API key and permissions
- 4. Check rate limit headers
- 5. Validate request payload format
- 6. Test with minimal example
Getting Help
If you continue to experience errors:
- Check our troubleshooting guide
- Search our GitHub issues
- Contact support with your request ID at support@saleswebhooks.com