Zum Hauptinhalt springen
Pro Plan15 minutesFortgeschrittene

API-Fehlerbehandlung

Behandeln Sie Zenovay API-Fehler elegant – Fehlercodes, Wiederholungsstrategien und Debugging-Techniken. Erfahren Sie mehr in dieser API-Integrations-Anleitung.

apierrorsdebuggingtroubleshootingbest-practices
Zuletzt aktualisiert:

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

FeldBeschreibung
successfalse bei Fehler, true bei Erfolg
error.codeMaschinenlesbarer Fehlercode (Großbuchstaben, z. B. RATE_LIMIT_EXCEEDED)
error.messageBenutzerfreundliche Fehlerbeschreibung
error.timestampISO 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)

CodeBeschreibung
200Anfrage erfolgreich

Erfolgreiche Responses verwenden den success: true-Wrapper:

{
  "success": true,
  "data": { /* ... */ },
  "timestamp": "2026-06-13T10:30:00.000Z"
}

Client-Fehler (4xx)

CodeFehlercodeBeschreibung
400VALIDATION_ERROR / MISSING_SITE_ID / GENERIC_ERRORUngültiger oder fehlender Parameter
401UNAUTHORIZEDUngültiger oder fehlender API-Schlüssel
403FORBIDDENAPI-Schlüssel hat keinen Zugriff auf die angeforderte Ressource
403API_PAID_PLAN_REQUIREDDie API erfordert einen kostenpflichtigen Plan (Free-Schlüssel sind blockiert)
404NOT_FOUNDRessource nicht gefunden
409CONFLICTRessourcenkonflikt (Duplikat)
429RATE_LIMIT_EXCEEDEDZu viele Anfragen dieses Minute
429MONTHLY_LIMIT_EXCEEDEDMonatliches Request-Kontingent erreicht

Server-Fehler (5xx)

CodeFehlercodeBeschreibung
500INTERNAL_ERROR / GENERIC_ERRORServerfehler

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:

HeaderBeschreibung
Retry-AfterSekunden zum Warten vor erneutem Versuch
X-RateLimit-LimitDein Pro-Minute-Anfrage-Limit
X-RateLimit-ResetISO 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

  1. Überprüfen Sie, ob Ihr API-Schlüssel gültig ist und mit zv_ beginnt
  2. Bestätigen Sie, dass Ihr Plan API-Zugriff umfasst (Pro oder höher)
  3. Überprüfen Sie die Endpunkt-URL und den Basispfad (/api/external/v1)
  4. Validieren Sie Abfrageparameter (z. B. site_id, range)
  5. Prüfen Sie die Netzwerkverbindung

Rate Limited

  1. Beachten Sie den Retry-After Header vor erneutem Versuch
  2. Steuern Sie Anfragen mit den X-RateLimit-* Headern
  3. Implementieren Sie exponentiellen Backoff für 5xx Responses
  4. Erwägen Sie ein Plan-Upgrade, wenn Sie das Limit konsistent überschreiten

Validierungsfehler

  1. Lesen Sie die error.message – sie nennt den fehlerhaften Parameter
  2. Überprüfen Sie, ob erforderliche Parameter vorhanden sind
  3. Verwenden Sie einen unterstützten range Wert (24h, 7d, 30d, 90d, 1y)
  4. Halten Sie Abfragezeichenfolgen innerhalb dokumentierter Längenlimits

Sporadische Fehler

  1. Implementieren Sie Wiederholungslogik mit Backoff
  2. Verwenden Sie das Circuit-Breaker-Muster
  3. Prüfen Sie auf Netzwerkprobleme
  4. Überwachen Sie die Zenovay-Statusseite

Nächste Schritte

War dieser Artikel hilfreich?