Erfahren Sie, wie Sie Zenovay API-Fehler mit korrekten Fehlercodes, Wiederholungsstrategien und Debugging-Techniken elegant behandeln.
Die Zenovay REST-API ist auf Pro, Scale und Enterprise-Plänen verfügbar. Anfragen, die mit einem Free-Plan-Schlüssel authentifiziert sind, werden mit einer 403 und dem Code API_PAID_PLAN_REQUIRED abgelehnt.
Format der Fehlerantwort
Alle API-Responses sind in ein success-Flag eingewickelt. Fehler geben success: false mit einem error-Objekt zurück:
{
"success": false,
"error": {
"message": "Rate limit exceeded (30 requests/minute). Try again in 42 seconds",
"code": "RATE_LIMIT_EXCEEDED",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
Der HTTP-Statuscode ist in der Response selbst (z. B. 429), nicht im Textkörper.
Antwortfelder
| Feld | Beschreibung |
|---|---|
success | false bei Fehler, true bei Erfolg |
error.code | Maschinenlesbarer Fehlercode (Großbuchstaben, z. B. RATE_LIMIT_EXCEEDED) |
error.message | Benutzerfreundliche Fehlerbeschreibung |
error.timestamp | ISO 8601-Zeitstempel, wann der Fehler generiert wurde |
Jede Response enthält auch einen x-request-id-Header (eine UUID). Fügen Sie ihn ein, wenn Sie sich an den Support wenden – so können wir eine einzelne Anfrage nachverfolgen.
HTTP-Statuscodes
Erfolgscodes (2xx)
| Code | Beschreibung |
|---|---|
200 | Anfrage erfolgreich |
Erfolgreiche Responses verwenden den success: true-Wrapper:
{
"success": true,
"data": { /* ... */ },
"timestamp": "2026-06-13T10:30:00.000Z"
}
Client-Fehler (4xx)
| Code | Fehlercode | Beschreibung |
|---|---|---|
400 | VALIDATION_ERROR / MISSING_SITE_ID / GENERIC_ERROR | Ungültiger oder fehlender Parameter |
401 | UNAUTHORIZED | Ungültiger oder fehlender API-Schlüssel |
403 | FORBIDDEN | API-Schlüssel hat keinen Zugriff auf die angeforderte Ressource |
403 | API_PAID_PLAN_REQUIRED | Die API erfordert einen kostenpflichtigen Plan (Free-Schlüssel sind blockiert) |
404 | NOT_FOUND | Ressource nicht gefunden |
409 | CONFLICT | Ressourcenkonflikt (Duplikat) |
429 | RATE_LIMIT_EXCEEDED | Zu viele Anfragen dieses Minute |
429 | MONTHLY_LIMIT_EXCEEDED | Monatliches Request-Kontingent erreicht |
Server-Fehler (5xx)
| Code | Fehlercode | Beschreibung |
|---|---|---|
500 | INTERNAL_ERROR / GENERIC_ERROR | Serverfehler |
Häufige Fehlercodes
Authentifizierungsfehler
Ein fehlender Schlüssel, ein fehlerhaft geformter Schlüssel (Zenovay-Schlüssel beginnen mit zv_) oder ein widerrufener Schlüssel geben alle 401 mit dem Code UNAUTHORIZED zurück. Die Nachricht teilt mit, welches:
// Fehlender API-Schlüssel
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Missing API key. Use Authorization: Bearer <key> or X-API-Key header",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
// Ungültiger oder widerrufener Schlüssel
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
Authentifizieren Sie sich mit einem Header:
Authorization: Bearer zv_YOUR_API_KEY
X-API-Key: zv_YOUR_API_KEY
Validierungsfehler
Fehlende oder fehlerhafte Parameter geben eine 400 mit einer Klartextnachricht zurück, die das Problem beschreibt:
// Fehlender erforderlicher Abfrageparameter
{
"success": false,
"error": {
"code": "MISSING_SITE_ID",
"message": "site_id parameter is required",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
// Ungültige Eingabe
{
"success": false,
"error": {
"code": "GENERIC_ERROR",
"message": "Query must be 500 characters or less",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
Rate-Limit-Fehler
Wenn Sie das Ratenlimit pro Minute überschreiten, erhalten Sie eine 429 mit RATE_LIMIT_EXCEEDED. Lesen Sie den Response-Header Retry-After (Sekunden), um zu erfahren, wie lange Sie warten müssen:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded (30 requests/minute). Try again in 45 seconds",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
Die Response enthält diese Header:
| Header | Beschreibung |
|---|---|
Retry-After | Sekunden zum Warten vor erneutem Versuch |
X-RateLimit-Limit | Dein Pro-Minute-Anfrage-Limit |
X-RateLimit-Reset | ISO 8601-Zeitstempel, wann das Fenster zurückgesetzt wird |
Das Ausschöpfen des monatlichen Kontingents gibt 429 mit MONTHLY_LIMIT_EXCEEDED und X-Usage-*-Headern (X-Usage-Monthly, X-Usage-Limit, X-Usage-Reset) zurück.
Ressourcenfehler
Das Anfordern einer Website, auf die Sie keinen Zugriff haben, oder einer Website, die nicht vorhanden ist, gibt 404 NOT_FOUND oder 403 FORBIDDEN zurück:
// Website nicht gefunden
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Website not found",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
// Schlüssel hat keinen Zugriff auf diese Website
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "API key does not have access to this website",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
Plan-Limit-Fehler
Einige Endpunkte erfordern einen höheren Plan als den aktuellen. Free-Schlüssel sind vollständig blockiert; Pro-Schlüssel sind von Scale-only-Endpunkten blockiert (z. B. die Natural-Language-Query-API):
// Free-Schlüssel ruft einen API-Endpunkt auf
{
"success": false,
"error": {
"code": "API_PAID_PLAN_REQUIRED",
"message": "The Zenovay API requires a paid plan. Upgrade to Pro or higher to use API keys.",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
// Pro-Schlüssel ruft einen Scale-only-Endpunkt auf
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "This endpoint requires a Scale plan or higher. Your current plan: Pro",
"timestamp": "2026-06-13T10:30:00.000Z"
}
}
Strategien zur Fehlerbehandlung
Grundlegende Fehlerbehandlung
async function callZenovayAPI(endpoint) {
try {
const response = await fetch(`https://api.zenovay.com/api/external/v1${endpoint}`, {
headers: {
'X-API-Key': API_KEY,
}
});
const body = await response.json();
if (!response.ok || body.success === false) {
throw new ZenovayAPIError(body.error, response.status, response.headers.get('x-request-id'));
}
return body.data;
} catch (error) {
if (error instanceof ZenovayAPIError) {
handleAPIError(error);
} else {
// Netzwerkfehler
console.error('Network error:', error);
}
throw error;
}
}
class ZenovayAPIError extends Error {
constructor(error, status, requestId) {
super(error?.message);
this.code = error?.code;
this.status = status;
this.requestId = requestId;
}
}
function handleAPIError(error) {
switch (error.code) {
case 'UNAUTHORIZED':
console.error('Invalid or missing API key');
break;
case 'API_PAID_PLAN_REQUIRED':
console.error('This API requires a paid plan');
break;
case 'RATE_LIMIT_EXCEEDED':
console.error('Rate limited - back off and retry');
break;
default:
console.error(`API error: ${error.message}`);
}
}
Wiederholung mit exponentiellem Backoff
Wiederholen Sie 429 und 5xx Responses. Für 429, beachten Sie den Retry-After-Header anstelle zu raten:
async function fetchWithRetry(url, options, maxRetries = 3) {
const retryableStatus = [429, 500, 502, 503, 504];
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
const body = await response.json();
if (response.ok && body.success !== false) {
return body.data;
}
// Wiederholen Sie nicht wiederholbare Client-Fehler
if (!retryableStatus.includes(response.status) || attempt === maxRetries) {
throw new ZenovayAPIError(body.error, response.status, response.headers.get('x-request-id'));
}
// Bevorzugen Sie den Retry-After des Servers (Sekunden) bei 429
let delay;
const retryAfter = response.headers.get('Retry-After');
if (response.status === 429 && retryAfter) {
delay = parseInt(retryAfter, 10) * 1000;
} else {
delay = Math.min(1000 * Math.pow(2, attempt), 30000); // Max 30s
}
console.log(`Retry attempt ${attempt + 1} after ${delay}ms`);
await sleep(delay);
} catch (error) {
if (error instanceof ZenovayAPIError) {
throw error;
}
// Netzwerkfehler - erneut versuchen
if (attempt === maxRetries) {
throw error;
}
await sleep(1000 * Math.pow(2, attempt));
}
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
class ZenovayAPIError extends Error {
constructor(error, status, requestId) {
super(error?.message);
this.code = error?.code;
this.status = status;
this.requestId = requestId;
}
}
Rate-Limit-Behandlung
Steuern Sie Ihre Anfragen mit den Rate-Limit-Headern, damit Sie vor einem 429 back-off:
class RateLimitedClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.queue = [];
this.processing = false;
this.rateLimitReset = null;
}
async request(endpoint) {
return new Promise((resolve, reject) => {
this.queue.push({ endpoint, resolve, reject });
this.processQueue();
});
}
async processQueue() {
if (this.processing || this.queue.length === 0) return;
// Warten, wenn Rate-Limit aktiv ist
if (this.rateLimitReset && Date.now() < this.rateLimitReset) {
const waitTime = this.rateLimitReset - Date.now();
setTimeout(() => this.processQueue(), waitTime);
return;
}
this.processing = true;
const { endpoint, resolve, reject } = this.queue.shift();
try {
const response = await fetch(`https://api.zenovay.com/api/external/v1${endpoint}`, {
headers: {
'X-API-Key': this.apiKey,
}
});
// Rate-Limit-Header prüfen
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
if (remaining === '0' && reset) {
this.rateLimitReset = new Date(reset).getTime();
}
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
this.rateLimitReset = Date.now() + ((parseInt(retryAfter, 10) || 60) * 1000);
// Anfrage erneut in die Warteschlange stellen
this.queue.unshift({ endpoint, resolve, reject });
} else {
const body = await response.json();
if (response.ok && body.success !== false) {
resolve(body.data);
} else {
reject(body.error);
}
}
} catch (error) {
reject(error);
} finally {
this.processing = false;
if (this.queue.length > 0) {
setImmediate(() => this.processQueue());
}
}
}
}
Circuit-Breaker-Muster
class CircuitBreaker {
constructor(options = {}) {
this.failureThreshold = options.failureThreshold || 5;
this.resetTimeout = options.resetTimeout || 30000;
this.failures = 0;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
this.nextAttempt = null;
}
async execute(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.failures = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failures++;
if (this.failures >= this.failureThreshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.resetTimeout;
}
}
}
// Verwendung
const breaker = new CircuitBreaker();
async function getAnalytics(websiteId) {
return breaker.execute(() =>
fetch(`https://api.zenovay.com/api/external/v1/analytics/${websiteId}?range=7d`, {
headers: {
'X-API-Key': API_KEY,
}
})
);
}
Debugging-Techniken
Debug-Modus aktivieren
// Alle API-Anfragen protokollieren
const DEBUG = process.env.ZENOVAY_DEBUG === 'true';
async function apiRequest(endpoint) {
if (DEBUG) {
console.log(`[Zenovay] Request: ${endpoint}`);
}
const response = await fetch(`https://api.zenovay.com/api/external/v1${endpoint}`, {
headers: { 'X-API-Key': API_KEY },
});
const result = await response.json();
if (DEBUG) {
console.log(`[Zenovay] Response: ${response.status} [${response.headers.get('x-request-id')}]`, JSON.stringify(result, null, 2));
}
return result;
}
Request-ID-Nachverfolgung
Protokollieren Sie den x-request-id Response-Header, wenn eine Anfrage fehlschlägt – der Support kann damit Ihre exakte Anfrage nachschlagen:
function handleError(error) {
console.error(`API Error [${error.requestId}]:`, error.message);
// In Fehlerberichte einbeziehen
if (typeof Sentry !== 'undefined') {
Sentry.captureException(error, {
extra: {
requestId: error.requestId,
code: error.code,
status: error.status
}
});
}
}
Vor dem Senden validieren
function validateQuery(params) {
const errors = [];
if (!params.site_id) {
errors.push('site_id is required');
}
if (params.range && !['24h', '7d', '30d', '90d', '1y'].includes(params.range)) {
errors.push("range must be one of 24h, 7d, 30d, 90d, 1y");
}
if (errors.length > 0) {
throw new Error(`Validation failed: ${errors.join(', ')}`);
}
return true;
}
Sprachspezifische Beispiele
Python
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
class ZenovayClient:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = 'https://api.zenovay.com/api/external/v1'
# Konfigurieren Sie die Wiederholungsstrategie
self.session = requests.Session()
retry = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry)
self.session.mount('https://', adapter)
def get_analytics(self, website_id, time_range='7d'):
response = self.session.get(
f'{self.base_url}/analytics/{website_id}',
params={'range': time_range},
headers={
'X-API-Key': self.api_key,
},
timeout=10
)
body = response.json()
if not response.ok or body.get('success') is False:
error = body.get('error', {})
raise ZenovayAPIError(
code=error.get('code'),
message=error.get('message'),
status=response.status_code,
request_id=response.headers.get('x-request-id')
)
return body['data']
class ZenovayAPIError(Exception):
def __init__(self, code, message, status, request_id=None):
self.code = code
self.message = message
self.status = status
self.request_id = request_id
super().__init__(f'[{code}] {message}')
Ruby
require 'net/http'
require 'json'
class ZenovayClient
class APIError < StandardError
attr_reader :code, :status, :request_id
def initialize(code:, message:, status:, request_id: nil)
@code = code
@status = status
@request_id = request_id
super(message)
end
end
def initialize(api_key)
@api_key = api_key
@base_url = 'https://api.zenovay.com/api/external/v1'
end
def get_analytics(website_id, time_range = '7d')
request("/analytics/#{website_id}?range=#{time_range}")
end
private
def request(endpoint, retries: 3)
uri = URI("#{@base_url}#{endpoint}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = @api_key
response = http.request(req)
result = JSON.parse(response.body)
if response.is_a?(Net::HTTPSuccess) && result['success'] != false
result['data']
else
error = result['error'] || {}
raise APIError.new(
code: error['code'],
message: error['message'],
status: response.code.to_i,
request_id: response['x-request-id']
)
end
rescue APIError
raise
rescue StandardError => e
retries -= 1
retry if retries > 0
raise e
end
end
Fehlerüberwachung
Integration mit Fehler-Tracking
// Sentry-Integration
import * as Sentry from '@sentry/node';
async function fetchAnalytics(websiteId) {
try {
return await apiRequest(`/analytics/${websiteId}`);
} catch (error) {
Sentry.captureException(error, {
tags: {
api_error_code: error.code,
endpoint: '/analytics'
},
extra: {
request_id: error.requestId,
website_id: websiteId
}
});
throw error;
}
}
Benachrichtigungen bei kritischen Fehlern
function handleError(error) {
// Benachrichtigung bei Authentifizierungs- / Plan-Problemen
if (error.code === 'UNAUTHORIZED' || error.code === 'API_PAID_PLAN_REQUIRED') {
sendAlert('API authentication failed', error);
}
// Benachrichtigung bei Quota-Erschöpfung
if (error.code === 'MONTHLY_LIMIT_EXCEEDED') {
sendAlert('Monthly API quota reached', error);
}
// Alle Fehler protokollieren
console.error(`[${error.code}] ${error.message}`, {
requestId: error.requestId,
status: error.status
});
}
Checkliste zur Fehlerbehebung
Anfrage schlägt fehl
- Überprüfen Sie, ob Ihr API-Schlüssel gültig ist und mit
zv_beginnt - Bestätigen Sie, dass Ihr Plan API-Zugriff umfasst (Pro oder höher)
- Überprüfen Sie die Endpunkt-URL und den Basispfad (
/api/external/v1) - Validieren Sie Abfrageparameter (z. B.
site_id,range) - Prüfen Sie die Netzwerkverbindung
Rate Limited
- Beachten Sie den
Retry-AfterHeader vor erneutem Versuch - Steuern Sie Anfragen mit den
X-RateLimit-*Headern - Implementieren Sie exponentiellen Backoff für
5xxResponses - Erwägen Sie ein Plan-Upgrade, wenn Sie das Limit konsistent überschreiten
Validierungsfehler
- Lesen Sie die
error.message– sie nennt den fehlerhaften Parameter - Überprüfen Sie, ob erforderliche Parameter vorhanden sind
- Verwenden Sie einen unterstützten
rangeWert (24h,7d,30d,90d,1y) - Halten Sie Abfragezeichenfolgen innerhalb dokumentierter Längenlimits
Sporadische Fehler
- Implementieren Sie Wiederholungslogik mit Backoff
- Verwenden Sie das Circuit-Breaker-Muster
- Prüfen Sie auf Netzwerkprobleme
- Überwachen Sie die Zenovay-Statusseite