Skip to main content

Error Handling

Learn how to handle errors from the Pdflet API.

Error Response Format

All errors return a consistent JSON format:
{
  "error": "error_code",
  "message": "Human-readable description",
  "details": {}
}

HTTP Status Codes

CodeNameDescription
400Bad RequestInvalid request parameters
401UnauthorizedMissing or invalid authentication
402Payment RequiredNo credits remaining
404Not FoundResource doesn’t exist
429Too Many RequestsRate limit exceeded
500Internal Server ErrorSomething went wrong on our end

Common Errors

Authentication Errors (401)

Missing API Key
{
  "error": "authentication_required",
  "message": "Authentication credentials were not provided."
}
Invalid API Key
{
  "error": "invalid_api_key",
  "message": "Invalid API key provided."
}
Solution: Verify your API key is correct and included in the X-API-Key header.

Validation Errors (400)

Missing HTML
{
  "error": "validation_error",
  "message": "Either 'html' or 'url' is required.",
  "details": {
    "html": ["This field is required."]
  }
}
Invalid Page Size
{
  "error": "validation_error",
  "message": "Invalid page size.",
  "details": {
    "page_size": ["Must be one of: A4, Letter, Legal, A3, A5"]
  }
}
Solution: Check your request body matches the API specification.

Credit Errors (402)

No Credits
{
  "error": "insufficient_credits",
  "message": "You have no credits remaining. Please upgrade your plan."
}
Solution: Upgrade your plan or wait for credits to reset.

Rate Limit Errors (429)

Rate Limited
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Please slow down.",
  "details": {
    "retry_after": 45
  }
}
Solution: Wait for retry_after seconds before retrying. Implement exponential backoff.

Not Found Errors (404)

Conversion Not Found
{
  "error": "not_found",
  "message": "Conversion not found."
}
Solution: Verify the conversion ID is correct and belongs to your account.

Handling Errors in Code

Python

import requests
from requests.exceptions import HTTPError

def create_pdf_safe(html):
    try:
        response = requests.post(
            "https://api.pdflet.dev/api/v1/pdf/",
            headers={"X-API-Key": API_KEY},
            json={"html": html}
        )
        response.raise_for_status()
        return response.json()

    except HTTPError as e:
        error_data = e.response.json()

        if e.response.status_code == 401:
            raise AuthenticationError(error_data["message"])
        elif e.response.status_code == 402:
            raise InsufficientCreditsError(error_data["message"])
        elif e.response.status_code == 429:
            retry_after = error_data.get("details", {}).get("retry_after", 60)
            time.sleep(retry_after)
            return create_pdf_safe(html)  # Retry
        else:
            raise ApiError(error_data["message"])

JavaScript

async function createPdfSafe(html) {
  const response = await fetch('https://api.pdflet.dev/api/v1/pdf/', {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ html })
  });

  if (!response.ok) {
    const error = await response.json();

    switch (response.status) {
      case 401:
        throw new Error(`Authentication failed: ${error.message}`);
      case 402:
        throw new Error('No credits remaining');
      case 429:
        const retryAfter = error.details?.retry_after || 60;
        await new Promise(r => setTimeout(r, retryAfter * 1000));
        return createPdfSafe(html); // Retry
      default:
        throw new Error(error.message);
    }
  }

  return response.json();
}

Retry Strategy

For transient errors (429, 500, 503), implement exponential backoff:
import time
import random

def retry_with_backoff(fn, max_retries=3):
    for attempt in range(max_retries):
        try:
            return fn()
        except (RateLimitError, ServerError) as e:
            if attempt == max_retries - 1:
                raise

            # Exponential backoff with jitter
            delay = (2 ** attempt) + random.uniform(0, 1)
            time.sleep(delay)
Always implement retry logic for rate limits (429) and server errors (5xx). These are often transient and succeed on retry.