# API Error Handling Guide


**Last Updated:** 2025-11-20

## Error Response Format

All API endpoints return consistent error responses:

```json
{
  "success": false,
  "message": "User-friendly error message",
  "correlationId": "TLI-20250111123456-a1b2c3d4",
  "debug": {
    "error": "Detailed error for debugging",
    "file": "/path/to/file.php",
    "line": 123
  }
}
```

## Correlation IDs

Every API request gets a unique correlation ID:

- **Format:** `{PREFIX}-{TIMESTAMP}-{RANDOM}`
- **Prefixes:**
  - `TLI` - Tools/calculator forms
  - `PRI` - Pricing/addon requests
  - Other prefixes may be used for different endpoints
- **Returned in:** `X-Correlation-ID` HTTP header
- **Included in:** JSON response body
- **Logged in:** Debug logs for server-side tracking

### Using Correlation IDs

When a request fails:

1. Check browser console for the correlation ID
2. Search server logs: `grep "{correlationId}" /path/to/log`
3. Find complete error trace with all context
4. Provide correlation ID when contacting support

## Debugging Production Errors

### 1. Check Health Endpoint

Visit: `/v2/api/health-check.php`

This endpoint reports:

- HubSpot token configuration status
- Form GUID availability
- PHP extensions
- Config file existence
- Log directory writability

Example response:

```json
{
  "timestamp": "2025-01-11T12:34:56+00:00",
  "php_version": "8.1.0",
  "environment": {
    "HUBSPOT_API_TOKEN_env": true,
    "ORDIO_HUBSPOT_LEAD_CAPTURE_FORM_GUID_env": true,
    "ORDIO_HUBSPOT_ADDON_FORM_GUID_env": false,
    "ORDIO_HUBSPOT_TOOLS_FORM_GUID_env": false
  },
  "required_extensions": {
    "curl": true,
    "json": true,
    "mbstring": true
  },
  "config_files": {
    "hubspot.php": true,
    "utm-validation.php": true,
    "shiftops-customers.php": true
  },
  "hubspot_token_test": "loaded",
  "hubspot_token_format": "valid",
  "hubspot_form_guids": {
    "lead_capture_modal": "configured",
    "addon_pricing_request": "configured",
    "tools_universal": "configured"
  },
  "status": "ok"
}
```

### 2. Get Correlation ID

**From Browser Console:**

- Network tab → Failed request → Response Headers → `X-Correlation-ID`
- OR Console logs will show: `CORRELATION ID: TLI-...`

**From User Report:**

- Error message may include: "Bitte kontaktiere den Support mit dieser ID: TLI-..."

### 3. Check Server Logs

**Log Locations:**

- Tools API: `v2/logs/tools_debug.log`
- Pricing API: `v2/logs/pricing_debug.log`
- PHP errors: Server-specific (usually `/var/log/php/error.log`)

**Search by Correlation ID:**

```bash
grep "TLI-20250111123456-a1b2c3d4" v2/logs/tools_debug.log
```

**Log Entry Format:**

```json
{
  "timestamp": "2025-01-11T12:34:56+00:00",
  "correlationId": "TLI-20250111123456-a1b2c3d4",
  "stage": "config_include_failure",
  "payload": {
    "error": "HubSpot API token not configured",
    "trace": "..."
  }
}
```

### 4. Review Error Trace

Log stages to look for:

- `request_received` - Initial request data
- `config_include_failure` - Config loading errors (CRITICAL)
- `php_error` - PHP warnings/errors
- `uncaught_exception` - Unhandled exceptions
- `shutdown_error` - Fatal errors
- `hubspot_request_prepared` - HubSpot submission attempt
- `hubspot_response` - HubSpot API response
- `hubspot_success` / `hubspot_failure` - Final outcome

## Common Errors

### 500 - HubSpot Configuration Error

**Symptoms:**

- Form submission fails immediately
- Console shows "Configuration error - please contact support"
- Correlation ID provided

**Cause:**

- Missing or invalid HubSpot API token
- Missing form GUID
- Config file inclusion error

**Solution:**

1. Check `/v2/api/health-check.php` for config status
2. Verify `HUBSPOT_API_TOKEN` environment variable is set
3. Check `/v2/config/shiftops-customers.php` for token definition
4. Ensure token format: `pat-{region}-{hash}` (e.g., `pat-eu1-abc123...`)
5. Verify form GUIDs are configured for requested forms

**Example Fix:**

```bash
# Set environment variable
export HUBSPOT_API_TOKEN="pat-eu1-your-token-here"

# OR update shiftops-customers.php
define('HUBSPOT_API_TOKEN', 'pat-eu1-your-token-here');
```

### 400 - Validation Error

**Symptoms:**

- Form submission rejected
- Error message indicates missing/invalid fields

**Cause:**

- Missing required fields (email, name, etc.)
- Invalid email format
- Invalid data types

**Solution:**

- Check request payload in console
- Verify all required fields are filled
- Ensure email format is valid
- Check data types match API expectations

### 404 - Endpoint Not Found

**Symptoms:**

- Request fails with 404
- "Not Found" error

**Cause:**

- Incorrect API URL
- File doesn't exist
- .htaccess rewrite issue

**Solution:**

- Verify API endpoint URL
- Check file exists: `ls v2/api/{endpoint}.php`
- Review `.htaccess` rewrite rules

### 429 - Rate Limit Exceeded

**Symptoms:**

- Intermittent failures
- "Too many requests" error

**Cause:**

- Too many requests to HubSpot API
- Rate limit exceeded

**Solution:**

- Wait before retrying
- Implement exponential backoff
- Check HubSpot API limits

### 503 - Service Unavailable

**Symptoms:**

- External service timeout
- HubSpot API unavailable

**Cause:**

- HubSpot API down
- Network connectivity issue
- Timeout

**Solution:**

- Check HubSpot status page
- Retry after delay
- Verify server internet connectivity

## Production Debugging Checklist

After deployment, if errors persist:

1. **Health Check**

   ```bash
   curl https://www.ordio.com/v2/api/health-check.php
   ```

2. **Get Correlation ID**

   - Browser Console → Network → Response Headers
   - OR User error message

3. **Check Logs**

   ```bash
   tail -f v2/logs/tools_debug.log
   tail -f v2/logs/pricing_debug.log
   ```

4. **Search by Correlation ID**

   ```bash
   grep "TLI-20250111123456" v2/logs/*.log
   ```

5. **Verify Environment**

   - HubSpot token set and valid
   - Form GUIDs configured
   - PHP extensions loaded
   - Log directories writable

6. **Test HubSpot Token**
   ```bash
   curl -H "Authorization: Bearer YOUR_TOKEN" \
     https://api.hubapi.com/crm/v3/objects/contacts
   ```

## Frontend Error Logging

### Tools Pages (Stundenlohnrechner, etc.)

Enhanced error logging includes:

- Error object details
- Response status and headers
- Correlation ID from headers
- Response body (raw and parsed)
- Stack trace

Example console output:

```
[Tools] Email Submission Failed
  Error object: Error: Server error
  Response status: 500
  Response headers: {x-correlation-id: "TLI-...", ...}
  CORRELATION ID: TLI-20250111123456-a1b2c3d4
  Response body (raw): {"success":false,"message":"...","correlationId":"..."}
  Response body (parsed): {success: false, ...}
```

### Pricing Forms (Enterprise, Add-ons)

Enhanced error logging includes:

- Request URL and method
- Response status and headers
- Correlation ID extraction
- Response body parsing
- User-friendly error display

Example console output:

```
[EnterpriseModal] Submission Failed
  Error: Error: Server error
  Message: Server error
  Request URL: /v2/api/addon-request.php
  Request method: POST
  Response status: 500
  Response headers: {x-correlation-id: "PRI-...", ...}
  CORRELATION ID from headers: PRI-20250111123456-a1b2c3d4
  Response body (raw): {"success":false,...}
  Response body (parsed): {success: false, correlationId: "PRI-...", ...}
  CORRELATION ID from body: PRI-20250111123456-a1b2c3d4
```

## Error Handler Architecture

### Initialization Order (CRITICAL)

All API endpoints follow this order:

1. **Enable PHP error logging** (FIRST)

   ```php
   ini_set('display_errors', 0);
   ini_set('log_errors', 1);
   ini_set('error_log', __DIR__ . '/../logs/debug.log');
   error_reporting(E_ALL);
   ```

2. **Define constants**

   ```php
   if (!defined('DEBUG_LOG')) {
       define('DEBUG_LOG', __DIR__ . '/../logs/debug.log');
   }
   ```

3. **Define helper functions** (logging, error handlers)

4. **Generate correlation ID**

   ```php
   $correlationId = 'PFX-' . date('YmdHis') . '-' . bin2hex(random_bytes(4));
   ```

5. **Register error handlers**

   ```php
   register_error_handlers($correlationId);
   ```

6. **Include config files** (WITH error protection)

   ```php
   try {
       require_once __DIR__ . '/../config/hubspot.php';
   } catch (Exception $e) {
       // Log and return error with correlation ID
   }
   ```

7. **Set headers** and process request

### Why This Order Matters

If config files are included BEFORE error handlers:

- Exceptions in config files are uncaught
- No correlation ID generated
- No structured logging
- User sees generic 500 error
- Debugging is impossible

## Best Practices

1. **Always include correlation IDs** in error responses
2. **Log before throwing** - Log context before exceptions
3. **Use structured logging** - JSON format for parsing
4. **Don't expose sensitive data** - Mask tokens in logs
5. **Provide actionable errors** - Tell users what to do
6. **Test error paths** - Simulate failures in development
7. **Monitor logs** - Set up alerts for errors
8. **Document expected errors** - Known failure modes

## Testing Error Handling

### Local Testing

1. **Test health endpoint:**

   ```bash
   curl http://localhost:8003/v2/api/health-check.php
   ```

2. **Test with invalid token:**

   ```php
   // Temporarily in shiftops-customers.php
   define('HUBSPOT_API_TOKEN', 'INVALID_TOKEN');
   ```

   - Submit form
   - Verify correlation ID in console
   - Check logs for detailed error
   - REVERT immediately

3. **Test with missing form GUID:**
   ```php
   // Temporarily in hubspot.php
   $formGuids = [
       'addon_pricing_request' => '', // Empty GUID
   ];
   ```
   - Submit form
   - Verify error handling
   - REVERT immediately

### Production Verification

After deployment:

1. Visit health endpoint
2. Verify all checks pass
3. Test one form submission
4. Check logs for clean execution
5. Monitor for errors in first 24 hours

## Support Workflow

When user reports error:

1. **Get correlation ID**

   - Ask user to check console
   - OR provide from error message

2. **Search logs**

   ```bash
   grep "{correlationId}" v2/logs/*.log
   ```

3. **Identify root cause**

   - Config error? → Fix token/GUID
   - Validation error? → Guide user
   - External API error? → Check status/retry

4. **Provide solution**

   - Specific fix based on error
   - Include correlation ID in ticket

5. **Follow up**
   - Verify fix resolves issue
   - Document for future reference

## Maintenance

### Log Rotation

Logs auto-rotate at 5MB:

```php
if (filesize($logPath) > 5 * 1024 * 1024) {
    rename($logPath, $logPath . '.' . date('YmdHis'));
}
```

### Log Cleanup

Remove old logs periodically:

```bash
find v2/logs -name "*.log.*" -mtime +30 -delete
```

### Monitoring

Set up alerts for:

- High error rates (>5% of requests)
- Config errors (immediate alert)
- HubSpot API failures (monitor for patterns)
- Correlation ID without resolution (stuck requests)

## Related Documentation

- Health Check Endpoint: `/v2/api/health-check.php`
- HubSpot Config: `/v2/config/hubspot.php`
- UTM Validation: `/v2/config/utm-validation.php`
- Logs Directory: `/v2/logs/`
- Project Ownership: [PROJECT_OWNERSHIP.md](PROJECT_OWNERSHIP.md) - Error email recipients and project contact information
