Skip to main content

Introduction

This guide covers all possible response codes, error formats, and best practices for handling errors when integrating with the Lovi API.

πŸ“Š HTTP Status Codes

Successful Responses

200 OK - Request Successful

Notification Processed:
{
  "success": true,
  "message": "Notification queued successfully",
  "notification_id": "uuid-notification-123",
  "scheduled_time": "2024-12-25T10:30:00Z"
}
Templates Retrieved:
{
  "templates": [
    {
      "id": "template_001",
      "name": "welcome_user",
      "status": "approved"
    }
  ],
  "total": 1
}
Template Created:
{
  "success": true,
  "message": "Template created successfully",
  "template": {
    "id": "new_template_123",
    "name": "order_confirmation",
    "status": "pending"
  }
}

Client Error Responses (4xx)

400 Bad Request - Invalid Parameters

Missing Required Field:
{
  "error": "validation_failed",
  "message": "Required field missing",
  "details": {
    "field": "contact.number",
    "reason": "This field is required"
  },
  "request_id": "req_123456789"
}
Invalid Parameter Format:
{
  "error": "validation_failed",
  "message": "Invalid parameter format",
  "details": {
    "field": "datetime_sending",
    "provided": "25-12-2024",
    "expected_format": "ISO 8601 (YYYY-MM-DDTHH:MM:SS)",
    "example": "2024-12-25T10:30:00"
  },
  "request_id": "req_123456790"
}
Invalid Phone Number:
{
  "error": "validation_failed",
  "message": "Invalid phone number format",
  "details": {
    "field": "contact.number",
    "provided": "+34-666-033-135",
    "expected_format": "Numbers only, no + or spaces",
    "example": "34666033135"
  },
  "request_id": "req_123456791"
}
Past Scheduled Time:
{
  "error": "validation_failed",
  "message": "Scheduled time must be in the future",
  "details": {
    "field": "datetime_sending",
    "provided": "2024-12-20T10:00:00",
    "current_time": "2024-12-20T15:30:00Z"
  },
  "request_id": "req_123456792"
}

401 Unauthorized - Authentication Failed

Invalid Access Key:
{
  "error": "unauthorized",
  "message": "Invalid or expired access key",
  "details": {
    "reason": "The provided access_key is not valid or has been revoked"
  },
  "request_id": "req_123456793"
}
Missing Access Key:
{
  "error": "unauthorized",
  "message": "Missing access key",
  "details": {
    "reason": "access_key parameter is required in the URL"
  },
  "request_id": "req_123456794"
}

403 Forbidden - Access Denied

Insufficient Permissions:
{
  "error": "forbidden",
  "message": "Insufficient permissions for this resource",
  "details": {
    "reason": "Your API key does not have permission to create templates"
  },
  "request_id": "req_123456795"
}
Company Access Denied:
{
  "error": "forbidden",
  "message": "Access denied to company resources",
  "details": {
    "reason": "API key is not associated with the requested company"
  },
  "request_id": "req_123456796"
}

404 Not Found - Resource Not Found

Template Not Found:
{
  "error": "template_not_found",
  "message": "Template 'welcome_user' not found or not approved",
  "details": {
    "template_name": "welcome_user",
    "language": "es_ES",
    "suggestion": "Check template name and approval status"
  },
  "request_id": "req_123456797"
}
Agent Not Found:
{
  "error": "agent_not_found",
  "message": "Voice agent not found",
  "details": {
    "agent_id": "uuid-invalid-agent",
    "suggestion": "Verify agent_id exists and is active"
  },
  "request_id": "req_123456798"
}

422 Unprocessable Entity - Business Logic Error

Template Not Approved:
{
  "error": "template_not_approved",
  "message": "Template is not in approved status",
  "details": {
    "template_name": "pending_template",
    "current_status": "pending",
    "required_status": "approved"
  },
  "request_id": "req_123456799"
}
Variable Mismatch:
{
  "error": "variable_mismatch",
  "message": "Template variables don't match provided data",
  "details": {
    "template_variables": ["name", "course"],
    "provided_variables": ["name", "email"],
    "missing": ["course"],
    "unexpected": ["email"]
  },
  "request_id": "req_123456800"
}

429 Too Many Requests - Rate Limit Exceeded

Rate Limit Hit:
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Try again in 60 seconds",
  "details": {
    "limit": 100,
    "window": "1 hour",
    "reset_time": "2024-12-20T16:30:00Z"
  },
  "retry_after": 60,
  "request_id": "req_123456801"
}
Daily Quota Exceeded:
{
  "error": "quota_exceeded",
  "message": "Daily notification quota exceeded",
  "details": {
    "quota": 10000,
    "used": 10000,
    "reset_time": "2024-12-21T00:00:00Z"
  },
  "request_id": "req_123456802"
}

Server Error Responses (5xx)

500 Internal Server Error

General Server Error:
{
  "error": "internal_error",
  "message": "An unexpected error occurred",
  "details": {
    "reason": "Internal server error"
  },
  "request_id": "req_123456803"
}

502 Bad Gateway

Upstream Service Error:
{
  "error": "service_unavailable",
  "message": "WhatsApp service temporarily unavailable",
  "details": {
    "service": "whatsapp_gateway",
    "estimated_recovery": "2024-12-20T16:00:00Z"
  },
  "request_id": "req_123456804"
}

503 Service Unavailable

Maintenance Mode:
{
  "error": "service_unavailable",
  "message": "Service temporarily unavailable for maintenance",
  "details": {
    "maintenance_window": "2024-12-20T02:00:00Z to 2024-12-20T04:00:00Z"
  },
  "request_id": "req_123456805"
}

πŸ”„ Retry Strategies

Status CodeActionRetry Strategy
400, 404, 422❌ Don’t retryFix request and try again
401, 403❌ Don’t retryRefresh authentication
429⏰ Retry with backoffUse retry_after header
500, 502, 503πŸ”„ Retry with exponential backoffMax 3 attempts

Implementation Example

async function makeAPIRequest(url, data, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data)
      });

      const result = await response.json();

      if (response.ok) {
        return result;
      }

      // Handle different error types
      if (response.status === 429) {
        const retryAfter = result.retry_after || 60;
        await sleep(retryAfter * 1000);
        continue;
      }

      if ([500, 502, 503].includes(response.status)) {
        if (attempt < maxRetries) {
          await sleep(Math.pow(2, attempt) * 1000); // Exponential backoff
          continue;
        }
      }

      // Don't retry for 4xx errors (except 429)
      throw new APIError(result.error, result.message, response.status);

    } catch (error) {
      if (attempt === maxRetries) throw error;
      await sleep(Math.pow(2, attempt) * 1000);
    }
  }
}

πŸ“ Best Practices

Error Logging

Always log these fields:
{
  "timestamp": "2024-12-20T15:30:00Z",
  "request_id": "req_123456789",
  "endpoint": "/notify",
  "method": "POST",
  "status_code": 400,
  "error_code": "validation_failed",
  "error_message": "Required field missing",
  "user_id": "user_123",
  "company_id": "company_456"
}

Error Handling Checklist

βœ… Pre-request Validation
  • Validate phone number format
  • Check required fields
  • Validate datetime format
  • Verify template exists
βœ… Request Monitoring
  • Log all API requests
  • Include request_id in logs
  • Monitor response times
  • Track error rates
βœ… Error Recovery
  • Implement appropriate retry logic
  • Cache authentication tokens
  • Handle rate limits gracefully
  • Provide meaningful error messages to users
βœ… User Experience
  • Show user-friendly error messages
  • Provide actionable feedback
  • Don’t expose internal error details
  • Offer alternatives when possible

Monitoring & Alerting

Key Metrics to Monitor:
  • Error rate per endpoint
  • Average response time
  • Rate limit hits
  • Authentication failures
  • Template not found errors
Alert Thresholds:
  • Error rate > 5%
  • Response time > 2 seconds
  • Rate limit hits > 10/hour
  • Authentication failures > 20/hour

πŸ› οΈ Development Tools

Error Testing

Test different error scenarios:
# Missing access_key
curl -X POST https://cloud.lovi.ai/functions/v1/notify \
  -H "Content-Type: application/json" \
  -d '{"contact":{"number":"34666033135"}}'

# Invalid phone number
curl -X POST https://cloud.lovi.ai/functions/v1/notify?access_key=test \
  -H "Content-Type: application/json" \
  -d '{"contact":{"number":"+34-666-033-135"}}'

# Past datetime
curl -X POST https://cloud.lovi.ai/functions/v1/notify?access_key=test \
  -H "Content-Type: application/json" \
  -d '{"datetime_sending":"2020-01-01T10:00:00"}'

Error Response Parser

class LoviAPIError extends Error {
  constructor(response) {
    super(response.message);
    this.name = 'LoviAPIError';
    this.code = response.error;
    this.statusCode = response.status;
    this.requestId = response.request_id;
    this.details = response.details;
  }

  isRetryable() {
    return [429, 500, 502, 503].includes(this.statusCode);
  }

  getRetryAfter() {
    return this.details?.retry_after || 60;
  }
}

🚨 Common Issues & Solutions

Authentication Issues

Problem: Invalid or expired access key Solution:
  1. Check if access_key is in URL parameters
  2. Verify the key hasn’t been revoked
  3. Ensure you’re using the correct company key

Template Issues

Problem: Template not found Solutions:
  1. Verify template name spelling
  2. Check template language matches
  3. Ensure template is approved
  4. Use GET /templates to list available templates

Rate Limiting

Problem: Too many requests Solutions:
  1. Implement exponential backoff
  2. Respect retry_after headers
  3. Batch requests when possible
  4. Monitor usage patterns

Data Validation

Problem: Validation failed Solutions:
  1. Validate data before sending
  2. Use proper phone number format
  3. Check datetime format
  4. Verify required fields are present
Remember to always include the request_id when contacting support for faster resolution of issues.