Skip to main content

Error Codes

The ColdSend API uses standard HTTP status codes and returns structured error responses.

HTTP Status Codes

CodeStatusDescription
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestInvalid request parameters
401UnauthorizedMissing or invalid API key
403ForbiddenInsufficient permissions
404Not FoundResource does not exist
409ConflictResource already exists
422Unprocessable EntityValidation error
429Too Many RequestsRate limit exceeded
500Internal Server ErrorPlatform error

Error Response Format

Errors are returned in a consistent JSON format:
{
  "detail": "Error message describing the issue"
}
For validation errors, the response includes field-specific details:
{
  "detail": [
    {
      "loc": ["body", "name"],
      "msg": "ensure this value has at least 8 characters",
      "type": "value_error.any_str.min_length"
    }
  ]
}

Authentication Errors

Missing API Key

{
  "detail": "API key required"
}
Status: 401 Unauthorized Solution: Include the X-API-Key header in your request.

Invalid or Revoked Key

{
  "detail": "Invalid or revoked API key"
}
Status: 401 Unauthorized Solution: Verify your API key is correct and has not been revoked in the dashboard.

Insufficient Scopes

{
  "detail": "Missing API key scopes: campaigns:write"
}
Status: 403 Forbidden Solution: Use an API key with the required scope.

Validation Errors

Field Required

{
  "detail": [
    {
      "loc": ["body", "name"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}
Solution: Include all required fields in your request.

Value Constraints

{
  "detail": [
    {
      "loc": ["body", "daily_limit_per_inbox"],
      "msg": "ensure this value is less than or equal to 100",
      "type": "value_error.number.not_le"
    }
  ]
}
Solution: Ensure field values are within allowed ranges.

Invalid Format

{
  "detail": [
    {
      "loc": ["body", "email_address"],
      "msg": "value is not a valid email address",
      "type": "value_error.email"
    }
  ]
}
Solution: Provide values in the correct format.

Campaign Errors

Campaign Not Found

{
  "detail": "Campaign 550e8400-e29b-41d4-a716-446655440000 not found"
}
Status: 404 Not Found Solution: Verify the campaign ID is correct and you have access to it.

Campaign Not in Draft

{
  "detail": "Can only update campaigns in DRAFT status"
}
Status: 400 Bad Request Solution: Campaigns can only be updated while in DRAFT status. Active or completed campaigns cannot be modified.

Step Progression Error

{
  "detail": "Cannot skip steps. Current step: 1, requested: 5"
}
Status: 400 Bad Request Solution: Progress through steps sequentially. You can only move to current_step + 1.

Variant Distribution Error

{
  "detail": "Variant distributions must sum to 100%, got 90%"
}
Status: 400 Bad Request Solution: Ensure all variant distribution_percent values sum to exactly 100.

Inbox Validation Error

{
  "detail": "Cannot assign inboxes: 1 inbox(es) failed validation"
}
Status: 400 Bad Request Solution: Check that all inboxes are active and properly configured.

Sender Account Errors

Email Already Exists

{
  "detail": "An email account with this address already exists."
}
Status: 409 Conflict Solution: Use a different email address or delete the existing account first.

Connection Failed

{
  "detail": "Failed to connect to your email provider. Please verify your credentials and app password settings."
}
Status: 400 Bad Request Solution: Verify your SMTP/IMAP credentials and server settings.

Inbox in Use

{
  "detail": "Inbox is assigned to a campaign and cannot be deleted. Remove from campaigns first."
}
Status: 400 Bad Request Solution: Remove the inbox from all campaigns before deleting.

Rate Limit Error

{
  "detail": "Rate limit exceeded. Retry after 60 seconds."
}
Status: 429 Too Many Requests Solution: Implement exponential backoff and respect rate limit headers.

Handling Errors

Python Example

import requests
import time

def api_request(method, url, **kwargs):
    max_retries = 3
    for attempt in range(max_retries):
        response = requests.request(method, url, **kwargs)
        
        if response.status_code == 200 or response.status_code == 201:
            return response.json()
        
        if response.status_code == 429:
            # Rate limited - wait and retry
            wait_time = 2 ** attempt
            time.sleep(wait_time)
            continue
        
        if response.status_code >= 400:
            error = response.json().get("detail", "Unknown error")
            raise Exception(f"API Error ({response.status_code}): {error}")
    
    raise Exception("Max retries exceeded")

Best Practices

  1. Always check status codes before processing responses
  2. Implement retry logic for 429 and 500 errors
  3. Log error details for debugging
  4. Handle validation errors by displaying field-specific messages
  5. Don’t retry 400 errors - fix the request instead