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
| Status | Description |
|---|---|
200 | Success |
201 | Created (for POST requests that create resources) |
400 | Bad Request — Invalid parameters or request body |
401 | Unauthorized — Missing or invalid API key |
403 | Forbidden — API key lacks required permissions |
404 | Not Found — Resource doesn’t exist |
429 | Too Many Requests — Rate limit exceeded |
500 | Internal 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
Authorizationheader 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.errorsarray 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: 45Resolution:
- Wait until
X-RateLimit-Resettimestamp - 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_abc123Resolution:
- 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
/resumeendpoint first - Check the resource’s
statefield
”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:
- Note the
X-Request-Idfrom the response headers - Check the status page for outages
- Contact support at support@vendodata.com with:
- The request ID
- The endpoint and method
- The request body (sanitize credentials)
- The full error response