Skip to main content

Overview

The Voyant API uses standard HTTP status codes to indicate success or failure of requests. Error responses include a JSON body with details about what went wrong.

Error response format

All errors return a JSON object with an error field:
{
  "error": "Error message description"
}
Some errors may include additional fields:
{
  "error": "Validation failed",
  "details": {
    "field": "email",
    "message": "Invalid email format"
  }
}

HTTP status codes

2xx Success

CodeStatusDescription
200OKRequest succeeded
201CreatedResource created successfully
204No ContentRequest succeeded with no response body

4xx Client errors

CodeStatusDescription
400Bad RequestInvalid request format or parameters
401UnauthorizedMissing or invalid Authorization token
403ForbiddenValid key but insufficient permissions
404Not FoundResource not found
409ConflictRequest conflicts with existing resource
422Unprocessable EntityValid format but invalid data
429Too Many RequestsRate limit exceeded

5xx Server errors

CodeStatusDescription
500Internal Server ErrorUnexpected server error
502Bad GatewayUpstream service error
503Service UnavailableTemporary service outage
504Gateway TimeoutRequest timeout

Common errors

400 Bad Request

Invalid request format, missing required fields, or malformed JSON.
{
  "error": "Invalid request"
}
Common causes:
  • Malformed JSON in request body
  • Missing required fields
  • Invalid parameter types
  • Invalid UUID format
How to fix:
  • Validate JSON before sending
  • Check required fields in documentation
  • Ensure correct data types
  • Use proper UUID v4 format

401 Unauthorized

Missing or invalid Authorization token.
{
  "error": "Unauthorized"
}
Common causes:
  • Missing Authorization: Bearer header
  • Invalid API key
  • Revoked API key
  • Extra spaces in API key
How to fix:
  • Verify Authorization header is included in request
  • Check for typos or extra characters
  • Generate new API key if needed
  • Ensure key hasn’t been revoked

404 Not Found

Requested resource doesn’t exist or you don’t have access.
{
  "error": "Not found"
}
Common causes:
  • Invalid resource ID
  • Resource deleted
  • No access to resource (wrong workspace)
  • Typo in endpoint URL
How to fix:
  • Verify resource ID is correct
  • Check resource still exists
  • Confirm resource belongs to your workspace
  • Review endpoint URL for typos

429 Rate Limit Exceeded

Too many requests in a short time period.
{
  "error": "Rate limit exceeded",
  "retry_after": 30
}
Common causes:
  • Exceeding 3,000 requests per minute
  • Surpassing the 30 requests per second burst window
  • Missing rate limit handling
How to fix:
  • Implement exponential backoff
  • Use retry_after value for delays
  • Cache responses when possible
  • Coordinate with support ahead of high-volume events

500 Internal Server Error

Unexpected server error.
{
  "error": "Internal server error"
}
Common causes:
  • Temporary service issue
  • Database connection problem
  • Upstream service failure
How to fix:
  • Retry request with exponential backoff
  • Contact support if persistent
  • Include X-Request-ID when reporting

Error handling best practices

1. Check status codes

Always check the HTTP status code before parsing the response:
const response = await fetch('https://api.voyantcloud.com/v1/products', {
  headers: { Authorization: `Bearer ${process.env.VOYANT_API_KEY}` }
});

if (!response.ok) {
const error = await response.json();
throw new Error(`API error (${response.status}): ${error.error}`);
}

const data = await response.json();

2. Implement retry logic

Use exponential backoff for retrying failed requests:
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const retryAfter = response.headers.get('retry-after') || (2 ** i);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }
      
      if (response.status >= 500) {
        await new Promise(resolve => setTimeout(resolve, (2 ** i) * 1000));
        continue;
      }
      
      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, (2 ** i) * 1000));
    }
  }
}

3. Log request IDs

Always log the X-Request-ID header for debugging:
const requestId = response.headers.get("x-request-id")
console.error(`API error: ${error.error}`, { requestId })
Include the request ID when contacting support for faster troubleshooting.

4. Handle rate limits

Respect rate limit headers to avoid throttling:
const limit = response.headers.get("x-ratelimit-limit")
const remaining = response.headers.get("x-ratelimit-remaining")
const reset = response.headers.get("x-ratelimit-reset")

if (remaining < 10) {
  console.warn(`Rate limit warning: ${remaining}/${limit} remaining`)
}

5. Validate inputs

Validate data before sending to avoid 400 errors:
function validatePriceRequest(data) {
  if (!data.productId || !isUUID(data.productId)) {
    throw new Error("Invalid productId")
  }

  if (!data.departureId || !isUUID(data.departureId)) {
    throw new Error("Invalid departureId")
  }

  if (!data.pax || data.pax.adults < 1) {
    throw new Error("At least one adult required")
  }

  return data
}

const validData = validatePriceRequest(requestData)

Error handling patterns

Graceful degradation

async function getProducts() {
  try {
    const response = await fetch("https://api.voyantcloud.com/v1/products", {
      headers: { Authorization: `Bearer ${process.env.VOYANT_API_KEY}` },
    })

    if (!response.ok) {
      console.error("Failed to fetch products:", await response.json())
      return [] // Return empty array instead of throwing
    }

    return await response.json()
  } catch (error) {
    console.error("Network error:", error)
    return [] // Fallback to empty array
  }
}

User-friendly messages

Map technical errors to user-friendly messages:
function getUserMessage(statusCode, error) {
  const messages = {
    400: "Invalid request. Please check your input.",
    401: "Authentication failed. Please check your Authorization token.",
    404: "Resource not found. It may have been deleted.",
    429: "Too many requests. Please try again in a moment.",
    500: "Server error. Please try again later.",
    503: "Service temporarily unavailable. Please try again.",
  }

  return messages[statusCode] || "An unexpected error occurred."
}

Circuit breaker pattern

Prevent cascading failures with circuit breaker:
class CircuitBreaker {
  constructor(threshold = 5, timeout = 60000) {
    this.failureCount = 0
    this.threshold = threshold
    this.timeout = timeout
    this.state = "CLOSED" // CLOSED, OPEN, HALF_OPEN
    this.nextAttempt = Date.now()
  }

  async call(fn) {
    if (this.state === "OPEN") {
      if (Date.now() < this.nextAttempt) {
        throw new Error("Circuit breaker is OPEN")
      }
      this.state = "HALF_OPEN"
    }

    try {
      const result = await fn()
      this.onSuccess()
      return result
    } catch (error) {
      this.onFailure()
      throw error
    }
  }

  onSuccess() {
    this.failureCount = 0
    this.state = "CLOSED"
  }

  onFailure() {
    this.failureCount++
    if (this.failureCount >= this.threshold) {
      this.state = "OPEN"
      this.nextAttempt = Date.now() + this.timeout
    }
  }
}

Debugging errors

Enable verbose logging

Add detailed logging for development:
const DEBUG = process.env.NODE_ENV === "development"

async function apiRequest(endpoint, options) {
  if (DEBUG) {
    console.log("Request:", { endpoint, options })
  }

  const response = await fetch(`https://api.voyantcloud.com${endpoint}`, options)

  if (DEBUG) {
    console.log("Response:", {
      status: response.status,
      headers: Object.fromEntries(response.headers),
      requestId: response.headers.get("x-request-id"),
    })
  }

  return response
}

Check API status

Before debugging, verify API status:
curl -I https://api.voyantcloud.com/v1/products

Test authentication

Isolate authentication issues:
curl https://api.voyantcloud.com/v1/products \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -v

Getting help

If you encounter persistent errors:
1

Review documentation

Verify your implementation matches the API reference
2

Collect information

  • Request ID (X-Request-ID) from response headers
  • Endpoint, method, and sanitized request payload
  • Response status code and body
  • Workspace ID and timestamp of the failure
3

Contact support

Email help@voyantcloud.com with the details above or open a ticket from the dashboard.