Errors & Status Codes

Try this endpoint in the playground →

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": "Invalid API key format. Keys must start with 'sk-dfir-'.",
    "request_id": "req_abc12345-6789-0123-4567-89abcdef0123"
  }
}

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
413Payload Too Large — request body exceeds size limitNo, reduce payload
415Unsupported Media Type — Content-Type must be application/jsonNo, fix Content-Type
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
missing_authorizationauthentication_errorMissing Authorization header
invalid_authorization_formatauthentication_errorAuthorization header must use the Bearer scheme
api_key_invalidauthentication_errorInvalid API key format
key_expiredauthentication_errorThis API key has expired
key_revokedauthentication_errorThis API key has been revoked
validation_service_unavailableauthentication_errorUnable to validate API key — try again later
insufficient_permissionsauthorization_errorKey lacks the required permission
plan_insufficientauthorization_errorEndpoint requires a higher plan
insufficient_creditsinsufficient_creditsNot enough credits
invalid_content_typeinvalid_requestContent-Type must be application/json
payload_too_largeinvalid_requestRequest body exceeds maximum size
invalid_jsoninvalid_requestRequest body is not valid JSON
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://api.dfir-lab.ch/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://api.dfir-lab.ch/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");
}