Error Codes and Troubleshooting
This page documents all error codes returned by the Ledly API and how to resolve them.
Error Response Format
All API errors follow this standard format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": []
}
}With Field-Level Details
Validation errors include field-specific information:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{
"field": "email",
"message": "Invalid email format",
"value": "not-an-email"
},
{
"field": "phone",
"message": "Phone number must include country code",
"value": "5551234567"
}
]
}
}HTTP Status Codes
| Status Code | Meaning | When It Occurs |
|---|---|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource created successfully |
| 204 | No Content | Request succeeded with no response body |
| 400 | Bad Request | Invalid request format or parameters |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource doesn’t exist |
| 409 | Conflict | Resource conflict (e.g., duplicate) |
| 422 | Unprocessable Entity | Valid request but business logic error |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server-side error |
| 503 | Service Unavailable | Service temporarily unavailable |
Authentication Errors (401)
INVALID_CREDENTIALS
Cause: Incorrect email or password during login.
Response:
{
"error": {
"code": "INVALID_CREDENTIALS",
"message": "Invalid email or password"
}
}Resolution:
- Verify email and password are correct
- Check for typos or extra whitespace
- Use password reset if forgotten
TOKEN_EXPIRED
Cause: JWT token has expired (tokens last 24 hours).
Response:
{
"error": {
"code": "TOKEN_EXPIRED",
"message": "Authentication token has expired",
"expired_at": "2024-12-25T10:30:00Z"
}
}Resolution:
- Login again to get a new token
- Use the
/api/auth/refreshendpoint to refresh before expiration
Example:
// Check token expiration before requests
if (isTokenExpired(token)) {
const { token: newToken } = await refreshToken();
// Retry request with new token
}TOKEN_INVALID
Cause: JWT token is malformed or tampered with.
Response:
{
"error": {
"code": "TOKEN_INVALID",
"message": "Authentication token is invalid"
}
}Resolution:
- Ensure token is correctly formatted
- Check for truncation or corruption
- Login again to get a valid token
API_KEY_INVALID
Cause: API key not found or incorrectly formatted.
Response:
{
"error": {
"code": "API_KEY_INVALID",
"message": "API key is invalid or has been revoked"
}
}Resolution:
- Verify API key starts with
vk_live_(production) orvk_test_(sandbox) - Check for typos or truncation
- Ensure key hasn’t been revoked
- Generate a new API key if needed
API_KEY_REVOKED
Cause: API key was manually revoked.
Response:
{
"error": {
"code": "API_KEY_REVOKED",
"message": "This API key has been revoked",
"revoked_at": "2024-12-20T15:00:00Z"
}
}Resolution:
- Generate a new API key in Settings → API Keys
- Update your integration with the new key
Authorization Errors (403)
INSUFFICIENT_PERMISSIONS
Cause: User or API key lacks required permissions.
Response:
{
"error": {
"code": "INSUFFICIENT_PERMISSIONS",
"message": "You don't have permission to perform this action",
"required_permission": "leads:write"
}
}Resolution:
- Check user role has necessary permissions
- Verify API key has required scopes
- Contact organization admin to grant permissions
IP_RESTRICTED
Cause: Request from unauthorized IP address.
Response:
{
"error": {
"code": "IP_RESTRICTED",
"message": "Access denied from this IP address",
"ip_address": "203.0.113.42",
"allowed_ips": ["198.51.100.0/24"]
}
}Resolution:
- Add your IP to API key’s allowed IPs
- Remove IP restrictions if not needed
- Use VPN or proxy from allowed IP range
ORGANIZATION_SUSPENDED
Cause: Organization account is suspended.
Response:
{
"error": {
"code": "ORGANIZATION_SUSPENDED",
"message": "Your organization account has been suspended",
"reason": "Payment overdue",
"suspended_at": "2024-12-20T00:00:00Z"
}
}Resolution:
- Contact [email protected]
- Update billing information
- Resolve any outstanding issues
Validation Errors (400)
VALIDATION_ERROR
Cause: Request data failed validation.
Response:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{
"field": "email",
"message": "Invalid email format",
"value": "not-an-email"
},
{
"field": "phone",
"message": "Phone number must be in E.164 format",
"value": "123-456-7890"
}
]
}
}Resolution:
- Fix each field listed in
details - Validate data client-side before submission
- Refer to API documentation for field requirements
Common Validation Issues:
| Field | Issue | Solution |
|---|---|---|
email | Invalid format | Use valid email: [email protected] |
phone | Missing country code | Include country code: +15551234567 |
password | Too weak | Min 8 chars, 1 uppercase, 1 number |
custom_fields | Invalid type | Match expected type (string, number, boolean) |
MISSING_REQUIRED_FIELD
Cause: Required field not provided.
Response:
{
"error": {
"code": "MISSING_REQUIRED_FIELD",
"message": "Required field is missing",
"field": "email"
}
}Resolution:
- Include all required fields in request
- Check API documentation for required fields
INVALID_EMAIL
Cause: Email address is invalid or from blocked domain.
Response:
{
"error": {
"code": "INVALID_EMAIL",
"message": "Email address is invalid",
"reason": "Domain has no MX records",
"email": "[email protected]"
}
}Resolution:
- Verify email is correctly spelled
- Check domain exists and has valid MX records
- Avoid disposable email providers (if blocked)
INVALID_PHONE_NUMBER
Cause: Phone number format is invalid.
Response:
{
"error": {
"code": "INVALID_PHONE_NUMBER",
"message": "Phone number format is invalid",
"phone": "123-456-7890",
"expected_format": "E.164 (+15551234567)"
}
}Resolution:
- Use E.164 format:
+[country code][number] - Examples:
+15551234567(US),+442071234567(UK)
Resource Errors (404)
LEAD_NOT_FOUND
Cause: Lead with specified ID doesn’t exist.
Response:
{
"error": {
"code": "LEAD_NOT_FOUND",
"message": "Lead with ID 'lead_abc123' not found",
"lead_id": "lead_abc123"
}
}Resolution:
- Verify lead ID is correct
- Check lead hasn’t been deleted
- Ensure you have access to the lead’s organization
RESOURCE_NOT_FOUND
Cause: Generic resource not found.
Response:
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "The requested resource was not found",
"resource_type": "vendor",
"resource_id": "vendor_xyz789"
}
}Resolution:
- Check resource ID is correct
- Verify resource exists in your organization
- Ensure proper authentication
Conflict Errors (409)
DUPLICATE_LEAD
Cause: Lead with same email already exists.
Response:
{
"error": {
"code": "DUPLICATE_LEAD",
"message": "A lead with this email already exists",
"duplicate_of": "lead_existing123",
"matched_fields": ["email"],
"similarity_score": 100
}
}Resolution:
- Update existing lead instead of creating new one
- Configure deduplication rules to allow duplicates
- Use different email address
EMAIL_ALREADY_REGISTERED
Cause: Email already used for another account.
Response:
{
"error": {
"code": "EMAIL_ALREADY_REGISTERED",
"message": "An account with this email already exists",
"email": "[email protected]"
}
}Resolution:
- Use different email address
- Login to existing account
- Use password reset if you forgot password
Business Logic Errors (422)
LEAD_REJECTED
Cause: Lead rejected by enrichment rules.
Response:
{
"error": {
"code": "LEAD_REJECTED",
"message": "Lead rejected by validation rules",
"reason": "Disposable email address not allowed",
"rule_id": "rule_reject_disposable",
"rule_name": "Reject Disposable Emails"
}
}Resolution:
- Fix the issue identified in
reason - Review enrichment rules if rejection is unexpected
- Contact admin to modify rules if needed
WEAK_PASSWORD
Cause: Password doesn’t meet security requirements.
Response:
{
"error": {
"code": "WEAK_PASSWORD",
"message": "Password does not meet security requirements",
"requirements": {
"min_length": 8,
"require_uppercase": true,
"require_lowercase": true,
"require_number": true,
"require_special": false
}
}
}Resolution:
- Use password with minimum 8 characters
- Include at least one uppercase letter
- Include at least one lowercase letter
- Include at least one number
INVALID_RESET_TOKEN
Cause: Password reset token is invalid or expired.
Response:
{
"error": {
"code": "INVALID_RESET_TOKEN",
"message": "Password reset token is invalid or has expired",
"token_age_hours": 25,
"max_age_hours": 24
}
}Resolution:
- Request a new password reset email
- Use reset link within 24 hours
- Check for typos in reset token
Rate Limit Errors (429)
RATE_LIMIT_EXCEEDED
Cause: Too many requests in time window.
Response:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"limit": 100,
"window": "1 minute",
"retry_after": 45
}
}Response Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1703505660
Retry-After: 45Resolution:
- Wait for
retry_afterseconds before retrying - Implement exponential backoff
- Reduce request frequency
- Contact support for higher limits
Example:
async function makeRequest(url) {
try {
const response = await fetch(url);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
return makeRequest(url); // Retry
}
return response;
} catch (error) {
console.error('Request failed:', error);
}
}Server Errors (500)
INTERNAL_SERVER_ERROR
Cause: Unexpected server error.
Response:
{
"error": {
"code": "INTERNAL_SERVER_ERROR",
"message": "An unexpected error occurred",
"request_id": "req_abc123xyz",
"timestamp": "2024-12-25T10:30:00Z"
}
}Resolution:
- Retry the request with exponential backoff
- If persists, contact support with
request_id - Check status page for ongoing incidents
SERVICE_UNAVAILABLE
Cause: Service temporarily unavailable (maintenance, overload).
Response:
{
"error": {
"code": "SERVICE_UNAVAILABLE",
"message": "Service temporarily unavailable",
"retry_after": 300
}
}Response Headers:
Retry-After: 300Resolution:
- Wait for
retry_afterseconds - Implement retry logic with backoff
- Check status page for maintenance windows
Integration-Specific Errors
CRM_SYNC_FAILED
Cause: Failed to sync lead to CRM.
Response:
{
"error": {
"code": "CRM_SYNC_FAILED",
"message": "Failed to sync lead to CRM",
"crm_type": "salesforce",
"crm_error": "INVALID_FIELD: Field 'Custom_Field__c' does not exist",
"lead_id": "lead_abc123"
}
}Resolution:
- Check CRM field mappings
- Verify CRM credentials are valid
- Review CRM error message for details
- Update field mappings in Settings → CRM
WEBHOOK_DELIVERY_FAILED
Cause: Failed to deliver webhook to your endpoint.
Response:
{
"error": {
"code": "WEBHOOK_DELIVERY_FAILED",
"message": "Failed to deliver webhook",
"webhook_id": "webhook_abc123",
"endpoint_url": "https://your-app.com/webhooks",
"response_status": 500,
"response_body": "Internal Server Error",
"attempts": 3,
"next_retry": "2024-12-25T12:00:00Z"
}
}Resolution:
- Check webhook endpoint is accessible
- Verify endpoint returns 2xx status
- Review webhook logs in Ledly dashboard
- Test webhook endpoint manually
EXPORT_FAILED
Cause: Failed to generate export.
Response:
{
"error": {
"code": "EXPORT_FAILED",
"message": "Failed to generate export",
"export_id": "export_abc123",
"reason": "Query timeout",
"row_count_attempted": 500000
}
}Resolution:
- Reduce date range or filters
- Try exporting in smaller batches
- Contact support for large exports
Best Practices
1. Handle All Error Cases
async function makeApiRequest(url, options) {
try {
const response = await fetch(url, options);
// Success
if (response.ok) {
return await response.json();
}
// Parse error
const error = await response.json();
// Handle specific errors
switch (error.error.code) {
case 'TOKEN_EXPIRED':
await refreshToken();
return makeApiRequest(url, options); // Retry
case 'RATE_LIMIT_EXCEEDED':
await sleep(error.error.retry_after * 1000);
return makeApiRequest(url, options); // Retry
case 'VALIDATION_ERROR':
console.error('Validation failed:', error.error.details);
throw error;
default:
throw error;
}
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}2. Implement Retry Logic
async function retryWithBackoff(fn, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
// Don't retry client errors (4xx)
if (error.status >= 400 && error.status < 500) {
throw error;
}
// Last attempt - throw error
if (attempt === maxRetries - 1) {
throw error;
}
// Wait with exponential backoff
const delay = Math.pow(2, attempt) * 1000;
await sleep(delay);
}
}
}3. Log Request IDs
async function makeRequest(url, options) {
try {
const response = await fetch(url, options);
const requestId = response.headers.get('X-Request-ID');
if (!response.ok) {
const error = await response.json();
console.error('Request failed:', {
requestId,
errorCode: error.error.code,
message: error.error.message
});
}
return response;
} catch (error) {
console.error('Request failed:', error);
}
}4. Validate Before Sending
function validateLead(lead) {
const errors = [];
// Email validation
if (!lead.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(lead.email)) {
errors.push({ field: 'email', message: 'Invalid email format' });
}
// Phone validation
if (lead.phone && !/^\+[1-9]\d{1,14}$/.test(lead.phone)) {
errors.push({ field: 'phone', message: 'Invalid phone format (use E.164)' });
}
if (errors.length > 0) {
throw new ValidationError(errors);
}
}5. Monitor Error Rates
const errorStats = {
total: 0,
byCode: {},
byStatus: {}
};
function trackError(error) {
errorStats.total++;
errorStats.byCode[error.code] = (errorStats.byCode[error.code] || 0) + 1;
errorStats.byStatus[error.status] = (errorStats.byStatus[error.status] || 0) + 1;
// Alert if error rate is high
if (errorStats.total > 100 && errorStats.byStatus[500] / errorStats.total > 0.05) {
alertDevTeam('High server error rate');
}
}Getting Help
If you encounter an error you can’t resolve:
- Check this page for error code documentation
- Review API logs in your Ledly dashboard
- Check status page at status.ledly.io
- Contact support at [email protected] with:
- Request ID (from
X-Request-IDheader) - Error code and message
- Steps to reproduce
- Timestamp of occurrence
- Request ID (from
Related Resources
- API Reference - Complete API documentation
- Rate Limits - Rate limiting details
- Authentication - Authentication guide
- Best Practices - Integration best practices