Skip to Content

Error Handling

The Vendo API uses standard HTTP status codes and returns consistent error response formats to help you handle errors gracefully.

Error Response Format

All errors follow this structure:

{ "error": { "code": "ERROR_CODE", "message": "Human-readable error description", "details": { // Additional context (optional) } } }

HTTP Status Codes

StatusDescription
200Success
201Created (for POST requests that create resources)
400Bad Request — Invalid parameters or request body
401Unauthorized — Missing or invalid API key
403Forbidden — API key lacks required permissions
404Not Found — Resource doesn’t exist
429Too Many Requests — Rate limit exceeded
500Internal Server Error — Something went wrong on our end

Error Codes Reference

Authentication Errors

UNAUTHORIZED

Status: 401

Missing or invalid API key.

{ "error": { "code": "UNAUTHORIZED", "message": "Missing API key. Include Authorization: Bearer <your-api-key>" } }

Resolution:

  • Ensure the Authorization header is present
  • Use the format Bearer YOUR_API_KEY (note the space after “Bearer”)
  • Verify the API key is correct and not revoked

FORBIDDEN

Status: 403

API key is valid but lacks permissions.

{ "error": { "code": "FORBIDDEN", "message": "This API key does not have the required scopes: apps.write" } }

Resolution:

  • Check the API key’s scopes in Settings > API Keys
  • Create a new key with the required permissions

Validation Errors

VALIDATION_ERROR

Status: 400

Request body failed validation.

{ "error": { "code": "VALIDATION_ERROR", "message": "Invalid request body", "details": { "errors": [ { "path": "name", "message": "Required" }, { "path": "schedule.frequencyUnit", "message": "Invalid enum value. Expected 'hours' | 'days' | 'weeks' | 'months'" } ] } } }

Resolution:

  • Check the details.errors array for specific field issues
  • Refer to the endpoint documentation for required fields and valid values

BAD_REQUEST

Status: 400

General bad request (business logic error).

{ "error": { "code": "BAD_REQUEST", "message": "Cannot trigger sync for an inactive source. Resume the source first." } }

Resolution:

  • Read the error message for specific guidance
  • Check the resource’s current state before performing actions

Resource Errors

NOT_FOUND

Status: 404

The requested resource doesn’t exist or isn’t accessible.

{ "error": { "code": "NOT_FOUND", "message": "App not found" } }

Resolution:

  • Verify the resource ID is correct
  • Ensure the resource belongs to your account
  • Check if the resource was deleted

Rate Limiting

RATE_LIMIT_EXCEEDED

Status: 429

Too many requests in the time window.

{ "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded. Try again in 45 seconds." } }

Response Headers:

X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1709510445 Retry-After: 45

Resolution:

  • Wait until X-RateLimit-Reset timestamp
  • Implement exponential backoff
  • Consider batching requests

Server Errors

INTERNAL_ERROR

Status: 500

An unexpected error occurred.

{ "error": { "code": "INTERNAL_ERROR", "message": "An unexpected error occurred. Please try again." } }

Response Headers:

X-Request-Id: req_1234567890_abc123

Resolution:

  • Retry the request after a brief delay
  • If the error persists, contact support with the X-Request-Id

Handling Errors in Code

JavaScript/TypeScript

async function makeApiRequest(endpoint: string, options: RequestInit = {}) { const response = await fetch(`https://app.vendodata.com/api/v1${endpoint}`, { ...options, headers: { 'Authorization': `Bearer ${process.env.VENDO_API_KEY}`, 'Content-Type': 'application/json', ...options.headers, }, }); const data = await response.json(); if (!response.ok) { const error = data.error; switch (error.code) { case 'UNAUTHORIZED': throw new Error('Invalid API key'); case 'RATE_LIMIT_EXCEEDED': const retryAfter = response.headers.get('Retry-After'); throw new Error(`Rate limited. Retry after ${retryAfter}s`); case 'VALIDATION_ERROR': const fields = error.details?.errors ?.map(e => `${e.path}: ${e.message}`) .join(', '); throw new Error(`Validation failed: ${fields}`); case 'NOT_FOUND': return null; // Handle missing resources gracefully default: throw new Error(error.message || 'API request failed'); } } return data.data; }

Python

import requests import time def make_api_request(endpoint, method='GET', data=None): url = f'https://app.vendodata.com/api/v1{endpoint}' headers = { 'Authorization': f'Bearer {os.environ["VENDO_API_KEY"]}', 'Content-Type': 'application/json' } response = requests.request(method, url, headers=headers, json=data) if response.status_code == 429: retry_after = int(response.headers.get('Retry-After', 60)) print(f'Rate limited. Waiting {retry_after}s...') time.sleep(retry_after) return make_api_request(endpoint, method, data) # Retry if not response.ok: error = response.json().get('error', {}) raise Exception(f"API Error [{error.get('code')}]: {error.get('message')}") return response.json().get('data')

Retry Strategy

For transient errors (429, 500, 502, 503, 504), implement exponential backoff:

async function withRetry(fn, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { try { return await fn(); } catch (error) { if (attempt === maxRetries - 1) throw error; // Check if error is retryable const isRetryable = [429, 500, 502, 503, 504].includes(error.status); if (!isRetryable) throw error; // Exponential backoff: 1s, 2s, 4s const delay = Math.pow(2, attempt) * 1000; await new Promise(resolve => setTimeout(resolve, delay)); } } }

Common Issues

”Invalid JSON in request body”

Cause: Malformed JSON in the request body.

Solution:

  • Validate your JSON before sending
  • Ensure strings are properly quoted
  • Check for trailing commas

”Source/Integration is not active”

Cause: Trying to sync an inactive resource.

Solution:

  • Call the /resume endpoint first
  • Check the resource’s state field

”App connection not found”

Cause: The referenced app ID doesn’t exist or was deleted.

Solution:

  • List apps to get valid IDs: GET /api/v1/apps
  • Ensure the app belongs to your account

Getting Help

If you encounter persistent errors:

  1. Note the X-Request-Id from the response headers
  2. Check the status page  for outages
  3. Contact support at support@vendodata.com with:
    • The request ID
    • The endpoint and method
    • The request body (sanitize credentials)
    • The full error response
Last updated on