Error Handling

Understanding and handling API errors

The telco.dev API uses conventional HTTP response codes and returns detailed error messages to help you handle issues gracefully.

HTTP Status Codes

CodeMeaning
200Success - Request completed successfully
400Bad Request - Invalid parameters or missing required fields
401Unauthorized - Missing or invalid API key
404Not Found - Resource doesn't exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Something went wrong on our end

Error Response Format

All errors return a JSON object with the following structure:

{
  "error": "error_code",
  "message": "Human-readable description of the error",
  "details": {
    // Optional additional information
  }
}

Fields

FieldTypeDescription
errorstringMachine-readable error code
messagestringHuman-readable error description
detailsobjectOptional additional context (varies by error type)

Error Codes

Authentication Errors (401)

unauthorized

Missing API key:

{
  "error": "unauthorized",
  "message": "API key required. Pass via X-API-Key header or api_key query param."
}

Invalid API key:

{
  "error": "unauthorized",
  "message": "Invalid API key"
}

Validation Errors (400)

invalid_request

Missing required parameter:

{
  "error": "invalid_request",
  "message": "Missing required parameter 'tn' (10-digit telephone number). Usage: /v1/lookup?tn=XXXXXXXXXX"
}

Invalid parameter format:

{
  "error": "invalid_request",
  "message": "Invalid 'tn' parameter: '415555'. Must be exactly 10 digits."
}

Not Found Errors (404)

not_found

Resource not found:

{
  "error": "not_found",
  "message": "No data found for NPA-NXX 415-555"
}

Endpoint not found:

{
  "error": "not_found",
  "message": "Endpoint not found: /v1/invalid"
}

Rate Limit Errors (429)

rate_limited

Per-minute limit exceeded:

{
  "error": "rate_limited",
  "message": "Per-minute rate limit exceeded. Limit: 6/minute. Resets in 45 seconds.",
  "details": {
    "limit_type": "minute",
    "limit": 6,
    "remaining": 0,
    "reset": 1705363260
  }
}

Daily limit exceeded:

{
  "error": "rate_limited",
  "message": "Daily rate limit exceeded. Limit: 100/day. Resets at 2025-01-16T00:00:00.000Z",
  "details": {
    "limit_type": "daily",
    "limit": 100,
    "remaining": 0,
    "reset": 1705449600
  }
}

Server Errors (500)

internal_error

{
  "error": "internal_error",
  "message": "An unexpected error occurred"
}

Handling Errors

JavaScript Example

async function lookupNumber(tn) {
  const response = await fetch(
    `https://api.telco.dev/v1/lookup/${tn}`,
    {
      headers: { "X-API-Key": process.env.TELCO_API_KEY }
    }
  );

  const data = await response.json();

  if (!response.ok) {
    switch (response.status) {
      case 400:
        throw new Error(`Invalid request: ${data.message}`);
      case 401:
        throw new Error("Invalid or missing API key");
      case 404:
        return null; // Number not found
      case 429:
        // Handle rate limiting
        const resetTime = data.details?.reset || Date.now() + 60000;
        const waitMs = resetTime * 1000 - Date.now();
        console.log(`Rate limited. Waiting ${waitMs}ms...`);
        await new Promise(r => setTimeout(r, waitMs));
        return lookupNumber(tn); // Retry
      case 500:
        throw new Error("Server error. Please try again later.");
      default:
        throw new Error(`API error: ${data.message}`);
    }
  }

  return data;
}

Python Example

import requests
import time
import os

class TelcoAPIError(Exception):
    def __init__(self, status_code, error_code, message, details=None):
        self.status_code = status_code
        self.error_code = error_code
        self.message = message
        self.details = details or {}
        super().__init__(f"{error_code}: {message}")

def lookup_number(tn, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(
            f"https://api.telco.dev/v1/lookup/{tn}",
            headers={"X-API-Key": os.environ["TELCO_API_KEY"]}
        )

        if response.ok:
            return response.json()

        data = response.json()

        if response.status_code == 404:
            return None  # Number not found

        if response.status_code == 429:
            # Rate limited - wait and retry
            reset_time = data.get("details", {}).get("reset", time.time() + 60)
            wait_time = max(0, reset_time - time.time())
            print(f"Rate limited. Waiting {wait_time:.0f}s...")
            time.sleep(wait_time)
            continue

        raise TelcoAPIError(
            response.status_code,
            data.get("error"),
            data.get("message"),
            data.get("details")
        )

    raise Exception("Max retries exceeded")

Best Practices

  1. Always check response status before processing data
  2. Handle 404s gracefully - not all numbers are in the database
  3. Implement retry logic for rate limits and server errors
  4. Use exponential backoff for retries to avoid overwhelming the API
  5. Log errors with full context for debugging
  6. Display user-friendly messages based on error codes