Skip to main content

Overview

The TerraQuake API uses standard HTTP status codes and returns consistent error response formats to help you identify and handle issues effectively. All errors include descriptive messages and metadata to assist with debugging.

Error Response Format

All error responses follow this standardized structure:
{
  "success": false,
  "status": 400,
  "message": "The limit parameter must be a positive integer greater than 0. Example: ?limit=50",
  "meta": {
    "timestamp": "2026-03-03T10:30:45.123Z"
  }
}

Error Response Fields

success
boolean
Always false for error responses
status
integer
HTTP status code (400, 404, 429, 500, 503, etc.)
message
string
Human-readable error description explaining what went wrong and how to fix it
meta
object
Additional metadata about the error

HTTP Status Codes

The API uses standard HTTP status codes to indicate the success or failure of requests:

Success Codes

200 OK
success
Request succeeded. The response body contains the requested data.

Client Error Codes (4xx)

400 Bad Request
error
Invalid request parameters or malformed request.Common causes:
  • Invalid pagination parameters (page < 1, limit < 1)
  • Invalid date formats
  • Missing required parameters
  • Invalid parameter types
404 Not Found
error
The requested resource does not exist.Common causes:
  • Invalid endpoint URL
  • Non-existent earthquake ID
  • Unavailable region
429 Too Many Requests
error
Rate limit exceeded.Solution: Wait for the duration specified in the Retry-After header before retrying.See Rate Limiting for more details.

Server Error Codes (5xx)

500 Internal Server Error
error
An unexpected error occurred on the server.What to do:
  • Retry the request after a brief delay
  • If the error persists, contact support
503 Service Unavailable
error
The upstream data source (INGV API) is temporarily unavailable.What to do:
  • Retry the request after a few seconds
  • Implement exponential backoff for retries

Common Error Scenarios

Invalid Pagination Parameters

Request:
curl "https://api.terraquakeapi.com/earthquakes/recent?page=0&limit=-5"
Response:
{
  "success": false,
  "status": 400,
  "message": "The page parameter must be a positive integer greater than 0. Example: ?page=2",
  "meta": {
    "timestamp": "2026-03-03T10:30:45.123Z"
  }
}

Rate Limit Exceeded

Request:
# 101st request in 1 second
curl "https://api.terraquakeapi.com/earthquakes/recent"
Response:
{
  "success": false,
  "status": 429,
  "message": "Rate limit exceeded: max 100 requests per second. Please slow down boi, cache responses where possible, and retry after the reset window.",
  "meta": {
    "timestamp": "2026-03-03T10:30:45.123Z"
  }
}
Response Headers:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1709481046
Retry-After: 1

Upstream Service Error

Request:
curl "https://api.terraquakeapi.com/earthquakes/recent"
Response:
{
  "success": false,
  "status": 500,
  "message": "HTTP error from the INGV source: 503 Service Unavailable",
  "meta": {
    "timestamp": "2026-03-03T10:30:45.123Z"
  }
}

Invalid Date Format

Request:
curl "https://api.terraquakeapi.com/earthquakes/date-range?startdate=invalid&enddate=2026-03-03"
Response:
{
  "success": false,
  "status": 400,
  "message": "Invalid date format. Use YYYY-MM-DD format. Example: ?startdate=2026-01-01",
  "meta": {
    "timestamp": "2026-03-03T10:30:45.123Z"
  }
}

Not Found Error

Request:
curl "https://api.terraquakeapi.com/earthquakes/nonexistent-endpoint"
Response:
{
  "success": false,
  "status": 404,
  "message": "Endpoint not found. Check the API documentation for available endpoints.",
  "meta": {
    "timestamp": "2026-03-03T10:30:45.123Z"
  }
}

Error Handling Implementation

The API uses a centralized error handler utility for consistent error responses:
const handleHttpError = (
  res,
  message = 'Internal server error. Your request cannot be processed at this time',
  code = 500
) => {
  res.status(code).json({
    success: false,
    status: code,
    message,
    meta: {
      timestamp: new Date().toISOString()
    }
  })
}
Source: /home/daytona/workspace/source/backend/src/utils/handleHttpError.js:5-19

Handling Errors in Your Code

JavaScript/TypeScript

async function getEarthquakes() {
  try {
    const response = await fetch(
      'https://api.terraquakeapi.com/earthquakes/recent?limit=50'
    );

    // Check if response is ok (status 200-299)
    if (!response.ok) {
      const error = await response.json();
      
      // Handle specific error codes
      switch (error.status) {
        case 400:
          console.error('Invalid request:', error.message);
          break;
        case 429:
          const retryAfter = response.headers.get('Retry-After');
          console.error(`Rate limited. Retry after ${retryAfter}s`);
          break;
        case 500:
        case 503:
          console.error('Server error. Retrying...');
          // Implement retry logic
          break;
        default:
          console.error('Unexpected error:', error.message);
      }
      
      throw new Error(error.message);
    }

    const data = await response.json();
    return data;
    
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}

Python

import requests
import time

def get_earthquakes(max_retries=3):
    url = 'https://api.terraquakeapi.com/earthquakes/recent'
    params = {'limit': 50}
    
    for attempt in range(max_retries):
        try:
            response = requests.get(url, params=params, timeout=10)
            
            # Check for errors
            if response.status_code == 400:
                error = response.json()
                raise ValueError(f"Bad request: {error['message']}")
            
            elif response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 1))
                print(f"Rate limited. Waiting {retry_after}s...")
                time.sleep(retry_after)
                continue
            
            elif response.status_code in [500, 503]:
                if attempt < max_retries - 1:
                    wait_time = 2 ** attempt  # Exponential backoff
                    print(f"Server error. Retrying in {wait_time}s...")
                    time.sleep(wait_time)
                    continue
                else:
                    error = response.json()
                    raise Exception(f"Server error: {error['message']}")
            
            elif response.status_code == 404:
                error = response.json()
                raise Exception(f"Not found: {error['message']}")
            
            # Raise for any other error status
            response.raise_for_status()
            
            return response.json()
            
        except requests.exceptions.Timeout:
            if attempt < max_retries - 1:
                print(f"Timeout. Retrying...")
                continue
            raise
        
        except requests.exceptions.ConnectionError:
            if attempt < max_retries - 1:
                print(f"Connection error. Retrying...")
                time.sleep(2 ** attempt)
                continue
            raise
    
    raise Exception("Max retries exceeded")

# Usage
try:
    data = get_earthquakes()
    print(f"Fetched {len(data['payload'])} earthquakes")
except Exception as e:
    print(f"Failed to fetch earthquakes: {e}")

Go

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "strconv"
    "time"
)

type ErrorResponse struct {
    Success bool   `json:"success"`
    Status  int    `json:"status"`
    Message string `json:"message"`
    Meta    struct {
        Timestamp string `json:"timestamp"`
    } `json:"meta"`
}

func getEarthquakes(maxRetries int) (map[string]interface{}, error) {
    url := "https://api.terraquakeapi.com/earthquakes/recent?limit=50"
    
    for attempt := 0; attempt < maxRetries; attempt++ {
        resp, err := http.Get(url)
        if err != nil {
            if attempt < maxRetries-1 {
                time.Sleep(time.Duration(1<<attempt) * time.Second)
                continue
            }
            return nil, err
        }
        defer resp.Body.Close()
        
        // Handle different status codes
        switch resp.StatusCode {
        case 200:
            var data map[string]interface{}
            json.NewDecoder(resp.Body).Decode(&data)
            return data, nil
            
        case 400:
            var errResp ErrorResponse
            json.NewDecoder(resp.Body).Decode(&errResp)
            return nil, fmt.Errorf("bad request: %s", errResp.Message)
            
        case 429:
            retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
            if retryAfter == 0 {
                retryAfter = 1
            }
            fmt.Printf("Rate limited. Waiting %ds...\n", retryAfter)
            time.Sleep(time.Duration(retryAfter) * time.Second)
            continue
            
        case 500, 503:
            if attempt < maxRetries-1 {
                waitTime := 1 << attempt
                fmt.Printf("Server error. Retrying in %ds...\n", waitTime)
                time.Sleep(time.Duration(waitTime) * time.Second)
                continue
            }
            body, _ := io.ReadAll(resp.Body)
            var errResp ErrorResponse
            json.Unmarshal(body, &errResp)
            return nil, fmt.Errorf("server error: %s", errResp.Message)
            
        default:
            var errResp ErrorResponse
            json.NewDecoder(resp.Body).Decode(&errResp)
            return nil, fmt.Errorf("error %d: %s", errResp.Status, errResp.Message)
        }
    }
    
    return nil, fmt.Errorf("max retries exceeded")
}

Best Practices

1

Always Check Response Status

Don’t assume requests succeed. Always check the HTTP status code or the success field in the response.
const response = await fetch(url);
if (!response.ok) {
  // Handle error
}
2

Implement Retry Logic

For server errors (5xx) and rate limits (429), implement retry logic with exponential backoff.
async function fetchWithRetry(url, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url);
      if (response.ok) return response.json();
      
      if (response.status >= 500) {
        // Exponential backoff: 1s, 2s, 4s
        await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
        continue;
      }
      
      throw new Error('Request failed');
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}
3

Log Errors for Debugging

Always log error details including the timestamp, status code, and message for debugging.
catch (error) {
  console.error('API Error:', {
    status: error.status,
    message: error.message,
    timestamp: error.meta?.timestamp,
    url: url
  });
}
4

Handle Rate Limits Gracefully

Use the Retry-After header to determine when to retry after hitting rate limits.See Rate Limiting for detailed examples.
5

Validate Input Before Sending

Validate parameters client-side before making requests to catch errors early.
function validateParams(page, limit) {
  if (page < 1) throw new Error('Page must be >= 1');
  if (limit < 1 || limit > 100) throw new Error('Limit must be 1-100');
}
6

Set Appropriate Timeouts

Set reasonable request timeouts to avoid hanging requests.
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000); // 10s

const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeout);

Error Monitoring

For production applications, implement error monitoring:
class APIErrorTracker {
  constructor() {
    this.errors = [];
  }

  track(error) {
    this.errors.push({
      status: error.status,
      message: error.message,
      timestamp: error.meta?.timestamp || new Date().toISOString(),
      url: error.url
    });

    // Send to monitoring service
    if (this.errors.length >= 10) {
      this.flush();
    }
  }

  flush() {
    // Send errors to your monitoring service (e.g., Sentry, DataDog)
    console.log('Flushing errors to monitoring service:', this.errors);
    this.errors = [];
  }
}

const errorTracker = new APIErrorTracker();

try {
  await fetch(url);
} catch (error) {
  errorTracker.track(error);
}

Common Questions

  • 500 (Internal Server Error): An unexpected error in the TerraQuake API itself
  • 503 (Service Unavailable): The upstream INGV data source is temporarily unavailable
Both should be retried with exponential backoff.
No. 4xx errors indicate client-side problems (invalid parameters, rate limits, etc.). Fix the request instead of retrying, except for 429 (rate limit) where you should wait and retry.
  • 429 errors: Use the Retry-After header value
  • 5xx errors: Use exponential backoff (1s, 2s, 4s, etc.)
  • Network errors: Start with 1s and increase exponentially
Error messages are designed to be descriptive. If you encounter an unclear error, check:
  1. The HTTP status code
  2. The timestamp in meta.timestamp
  3. Your request parameters
If the issue persists, contact support with the error details.

Build docs developers (and LLMs) love