Errors & Status Codes

The DFIR Suite API uses conventional HTTP status codes and returns structured JSON error bodies so you can handle failures programmatically.

Error Response Format

Every error response follows a consistent JSON structure:

{
  "error": {
    "type": "authentication_error",
    "code": "api_key_invalid",
    "message": "The API key provided is not valid."
  }
}

HTTP Status Codes

StatusMeaningRetry?
200Success
400Bad Request — invalid inputNo, fix request
401Unauthorized — invalid/missing keyNo, check key
402Payment Required — insufficient creditsNo, add credits
403Forbidden — wrong permissions or planNo, upgrade
429Rate LimitedYes, after Retry-After
500Internal ErrorYes, with backoff
503Service UnavailableYes, with backoff

Error Types

authentication_error

API key issues — missing, invalid, expired, or revoked.

authorization_error

Permission or plan issues — the key lacks access to the requested resource.

invalid_request

Bad input — missing fields, wrong types, or malformed request body.

rate_limit_exceeded

Too many requests — you have exceeded your rate limit window.

insufficient_credits

Out of credits — top up your account to continue making requests.

internal_error

Server error — something went wrong on our end. Safe to retry with backoff.

service_unavailable

Upstream down — a dependent service is temporarily unavailable.

Common Error Codes

CodeTypeMessage
api_key_missingauthentication_errorAPI key is required
api_key_invalidauthentication_errorThe API key is invalid
api_key_expiredauthentication_errorAPI key has expired
api_key_revokedauthentication_errorAPI key has been revoked
insufficient_permissionsauthorization_errorKey lacks required permission
plan_requiredauthorization_errorFeature requires higher plan
insufficient_creditsinsufficient_creditsNot enough credits
rate_limit_exceededrate_limit_exceededRate limit exceeded

Handling Errors

Always check the HTTP status code and parse the error body to decide whether to retry or surface the error to the user.

Python
import requests
import time

def analyze_email(raw_email: str, api_key: str, max_retries: int = 3):
    url = "https://dfir-lab.ch/api/v1/phishing/analyze"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }

    for attempt in range(max_retries):
        resp = requests.post(url, json={"raw_email": raw_email}, headers=headers)

        if resp.status_code == 200:
            return resp.json()

        error = resp.json().get("error", {})

        # Don't retry client errors (except rate limits)
        if resp.status_code == 429:
            retry_after = int(resp.headers.get("Retry-After", 5))
            time.sleep(retry_after)
            continue

        if resp.status_code in (500, 503):
            time.sleep(2 ** attempt)  # exponential backoff
            continue

        # 400, 401, 402, 403 — not retryable
        raise Exception(
            f"API error {resp.status_code}: "
            f"[{error.get('code')}] {error.get('message')}"
        )

    raise Exception("Max retries exceeded")
JavaScript
async function analyzeEmail(rawEmail, apiKey, maxRetries = 3) {
  const url = "https://dfir-lab.ch/api/v1/phishing/analyze";

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const resp = await fetch(url, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ raw_email: rawEmail }),
    });

    if (resp.ok) return resp.json();

    const { error } = await resp.json();

    // Rate limited — wait and retry
    if (resp.status === 429) {
      const retryAfter = parseInt(resp.headers.get("Retry-After") || "5");
      await new Promise((r) => setTimeout(r, retryAfter * 1000));
      continue;
    }

    // Server errors — exponential backoff
    if (resp.status >= 500) {
      await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
      continue;
    }

    // Client errors — not retryable
    throw new Error(
      `API error ${resp.status}: [${error?.code}] ${error?.message}`
    );
  }

  throw new Error("Max retries exceeded");
}