Documentation Index
Fetch the complete documentation index at: https://docs.buena.ai/llms.txt
Use this file to discover all available pages before exploring further.
The Buena.ai API uses conventional HTTP status codes and returns detailed error information to help you debug issues quickly.
All errors follow a consistent JSON format:
{
"error": true,
"code": "ERROR_CODE",
"message": "Human-readable error description",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"details": {
"field": "Additional context when applicable"
}
}
Fields
| Field | Description |
|---|
error | Always true for error responses |
code | Machine-readable error code |
message | Human-readable error description |
version | API version |
timestamp | ISO 8601 timestamp of the error |
details | Additional context (optional) |
HTTP Status Codes
2xx Success
200 OK - Request succeeded - 201 Created - Resource created - 204 No
Content - Request succeeded, no content
4xx Client Errors
400 Bad Request - Invalid request - 401 Unauthorized - Invalid API key
403 Forbidden - Insufficient permissions - 404 Not Found - Resource
not found - 429 Too Many Requests - Rate limited
5xx Server Errors
500 Internal Server Error - Server issue - 502 Bad Gateway - Upstream
error - 503 Service Unavailable - Temporary unavailability
Common Error Codes
Authentication Errors
UNAUTHORIZED (401)
{
"error": true,
"code": "UNAUTHORIZED",
"message": "Invalid API key",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z"
}
Causes:
- Missing
x-api-key header
- Invalid API key format
- Expired API key
- Deactivated API key
PERMISSION_DENIED (403)
{
"error": true,
"code": "PERMISSION_DENIED",
"message": "Insufficient permissions",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"permissionHelp": {
"required": "linkedin:schedule",
"available": ["linkedin:read"],
"documentation": "https://docs.buena.ai/authentication"
}
}
Causes:
- API key lacks required permission
- Attempting to access restricted resource
Validation Errors
VALIDATION_ERROR (400)
{
"error": true,
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"details": {
"fields": {
"email": "Invalid email format",
"firstName": "Field is required"
}
}
}
Causes:
- Missing required fields
- Invalid field formats
- Invalid field values
INVALID_LINKEDIN_URL (400)
{
"error": true,
"code": "INVALID_LINKEDIN_URL",
"message": "Invalid LinkedIn profile URL format",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"details": {
"providedUrl": "https://example.com/profile",
"expectedFormat": "https://linkedin.com/in/username"
}
}
Rate Limiting Errors
RATE_LIMIT_EXCEEDED (429)
{
"error": true,
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again in 45 seconds.",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"retryAfter": 45,
"rateLimitInfo": {
"limit": 60,
"remaining": 0,
"reset": 1640995245,
"window": "minute"
}
}
Resource Errors
NOT_FOUND (404)
{
"error": true,
"code": "NOT_FOUND",
"message": "Lead not found",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"details": {
"resource": "lead",
"id": "lead_abc123"
}
}
DUPLICATE_RESOURCE (409)
{
"error": true,
"code": "DUPLICATE_RESOURCE",
"message": "Lead with this email already exists",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"details": {
"field": "email",
"value": "john@example.com",
"existingId": "lead_xyz789"
}
}
Integration Errors
LINKEDIN_NOT_CONNECTED (400)
{
"error": true,
"code": "LINKEDIN_NOT_CONNECTED",
"message": "LinkedIn account not connected",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"details": {
"action": "Connect your LinkedIn account in the dashboard",
"dashboardUrl": "https://app.buena.ai/integrations/linkedin"
}
}
ENRICHMENT_CREDITS_EXHAUSTED (402)
{
"error": true,
"code": "ENRICHMENT_CREDITS_EXHAUSTED",
"message": "Insufficient enrichment credits",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"details": {
"remaining": 0,
"required": 5,
"upgradeUrl": "https://app.buena.ai/billing"
}
}
Error Handling Best Practices
Always check the HTTP status code before parsing the response:async function makeRequest(url, options) {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
throw new APIError(response.status, error);
}
return response.json();
}
class APIError extends Error {
constructor(status, errorData) {
super(errorData.message);
this.status = status;
this.code = errorData.code;
this.details = errorData.details;
}
}
Handle Specific Error Codes
Different errors require different handling strategies:async function handleAPICall() {
try {
return await makeRequest('/leads', options);
} catch (error) {
switch (error.code) {
case 'UNAUTHORIZED':
// Refresh or request new API key
await refreshAPIKey();
break;
case 'PERMISSION_DENIED':
// Log permission issue, contact admin
console.error('Missing permission:', error.details?.permissionHelp);
break;
case 'RATE_LIMIT_EXCEEDED':
// Wait and retry
await new Promise(resolve =>
setTimeout(resolve, error.retryAfter * 1000)
);
return handleAPICall(); // Retry
case 'VALIDATION_ERROR':
// Fix validation issues
console.error('Validation errors:', error.details?.fields);
break;
default:
// Log unexpected error
console.error('Unexpected error:', error);
}
throw error;
}
}
Retry transient errors with exponential backoff:async function retryableRequest(apiCall, maxRetries = 3) {
const retryableCodes = [
'RATE_LIMIT_EXCEEDED',
'INTERNAL_SERVER_ERROR',
'SERVICE_UNAVAILABLE'
];
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await apiCall();
} catch (error) {
const isLastAttempt = attempt === maxRetries - 1;
const isRetryable = retryableCodes.includes(error.code);
if (isLastAttempt || !isRetryable) {
throw error;
}
const delay = error.retryAfter ?
error.retryAfter * 1000 :
Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
Log errors with appropriate detail levels:function logError(error, context = {}) {
const logData = {
timestamp: new Date().toISOString(),
status: error.status,
code: error.code,
message: error.message,
context,
...error.details
};
// Different log levels based on error type
if (error.status >= 500) {
console.error('Server error:', logData);
} else if (error.status === 429) {
console.warn('Rate limited:', logData);
} else if (error.status >= 400) {
console.info('Client error:', logData);
}
// Send to monitoring service
sendToMonitoring(logData);
}
Language-Specific Examples
JavaScript/TypeScript
interface APIError {
error: boolean;
code: string;
message: string;
version: string;
timestamp: string;
details?: any;
}
class BuenaAPIClient {
private apiKey: string;
constructor(apiKey: string) {
this.apiKey = apiKey;
}
async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const response = await fetch(`https://api.buena.ai/api/v2${endpoint}`, {
...options,
headers: {
"x-api-key": this.apiKey,
"Content-Type": "application/json",
...options.headers,
},
});
const data = await response.json();
if (!response.ok) {
throw new BuenaAPIError(response.status, data);
}
return data;
}
}
class BuenaAPIError extends Error {
constructor(public status: number, public errorData: APIError) {
super(errorData.message);
this.name = "BuenaAPIError";
}
get code() {
return this.errorData.code;
}
get details() {
return this.errorData.details;
}
}
Python
import requests
from typing import Dict, Any, Optional
import time
class BuenaAPIError(Exception):
def __init__(self, status_code: int, error_data: Dict[str, Any]):
self.status_code = status_code
self.error_data = error_data
super().__init__(error_data.get('message', 'Unknown error'))
@property
def code(self) -> str:
return self.error_data.get('code', 'UNKNOWN')
@property
def details(self) -> Optional[Dict[str, Any]]:
return self.error_data.get('details')
class BuenaAPIClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = 'https://api.buena.ai/api/v2'
def request(
self,
endpoint: str,
method: str = 'GET',
json_data: Optional[Dict] = None,
max_retries: int = 3
) -> Dict[str, Any]:
headers = {
'x-api-key': self.api_key,
'Content-Type': 'application/json'
}
for attempt in range(max_retries):
try:
response = requests.request(
method=method,
url=f'{self.base_url}{endpoint}',
headers=headers,
json=json_data
)
if response.ok:
return response.json()
error_data = response.json()
error = BuenaAPIError(response.status_code, error_data)
# Handle specific error types
if error.code == 'RATE_LIMIT_EXCEEDED':
if attempt < max_retries - 1:
retry_after = error_data.get('retryAfter', 2 ** attempt)
time.sleep(retry_after)
continue
raise error
except requests.RequestException as e:
if attempt == max_retries - 1:
raise e
time.sleep(2 ** attempt)
Error Monitoring
Setting Up Alerts
class ErrorMonitor {
constructor(alertThreshold = 0.05) {
this.alertThreshold = alertThreshold; // 5% error rate
this.errorCounts = new Map();
this.totalRequests = 0;
}
trackRequest(isError, errorCode = null) {
this.totalRequests++;
if (isError) {
const count = this.errorCounts.get(errorCode) || 0;
this.errorCounts.set(errorCode, count + 1);
this.checkAlertThreshold();
}
}
checkAlertThreshold() {
const totalErrors = Array.from(this.errorCounts.values()).reduce(
(sum, count) => sum + count,
0
);
const errorRate = totalErrors / this.totalRequests;
if (errorRate >= this.alertThreshold) {
this.sendAlert(errorRate, this.errorCounts);
}
}
sendAlert(errorRate, errorCounts) {
console.error(`High error rate detected: ${(errorRate * 100).toFixed(2)}%`);
console.error("Error breakdown:", Object.fromEntries(errorCounts));
// Send to monitoring service (Datadog, New Relic, etc.)
}
}
Need Help?
If you’re experiencing persistent errors or need assistance:
Check Status Page
See if there are any known issues
Contact Support
Email our support team with error details
Discord Community
Get help from other developers
Documentation
Review the full API reference
When contacting support, please include:
- API key prefix (first 8 characters)
- Error response with timestamp
- Request details (endpoint, method, payload)
- Expected vs actual behavior