Skip to main content

Overview

This guide covers how to handle errors from the Cred Protocol API, including common error codes, error response formats, and best practices for building resilient applications.

Error Response Format

All API errors return a JSON response with a detail field:
{
  "detail": "Error message describing the issue"
}
Some errors may include additional fields:
{
  "detail": "Validation error",
  "errors": [
    {
      "field": "address",
      "message": "Invalid Ethereum address format"
    }
  ]
}

HTTP Status Codes

Client Errors (4xx)

StatusNameDescription
400Bad RequestInvalid request parameters
401UnauthorizedMissing or invalid API key
403ForbiddenInsufficient permissions
404Not FoundResource not found
422Unprocessable EntityValidation error
429Too Many RequestsRate limit exceeded

Server Errors (5xx)

StatusNameDescription
500Internal Server ErrorUnexpected server error
502Bad GatewayUpstream service error
503Service UnavailableService temporarily unavailable
504Gateway TimeoutRequest timed out

Common Errors and Solutions

{ "detail": "Invalid Ethereum address format" }
Causes:
  • Malformed Ethereum address
  • Invalid ENS name
  • Missing required parameters
Solutions:
  • Validate addresses before making requests
  • Use checksummed addresses when possible
  • Verify ENS names resolve correctly
import { isAddress } from 'viem';

function validateAddress(address) {
  // Check if it's a valid address or ENS name
  if (isAddress(address)) return true;
  if (address.endsWith('.eth')) return true;
  return false;
}
{ "detail": "Invalid or missing API key" }
Causes:
  • Missing Authorization header
  • Invalid API key format
  • Revoked API key
Solutions:
  • Ensure header format is Bearer YOUR_API_KEY
  • Check for typos in the API key
  • Verify the key hasn’t been revoked
  • Generate a new key if needed
// Correct format
headers: {
  'Authorization': 'Bearer sk_live_abc123'
}

// Common mistakes
headers: {
  'Authorization': 'sk_live_abc123'  // Missing "Bearer "
  'Api-Key': 'sk_live_abc123'        // Wrong header name
}
{ "detail": "Insufficient permissions" }
Causes:
  • Accessing a feature not in your plan
  • Account restrictions
Solutions:
  • Check your plan features in the Dashboard
  • Upgrade your plan if needed
  • Contact support for account issues
{ "detail": "Address not found or has no on-chain activity" }
Causes:
  • Address has never been used on-chain
  • ENS name doesn’t exist
  • Incorrect endpoint path
Solutions:
  • Verify the address exists on Etherscan
  • Check ENS name resolution
  • Verify the endpoint URL
async function getScoreWithFallback(address) {
  try {
    const response = await fetch(`${API_URL}/api/v2/score/${address}`, {
      headers: { 'Authorization': `Bearer ${API_KEY}` }
    });
    
    if (response.status === 404) {
      // Address has no activity - return a default or handle gracefully
      return { score: null, message: 'No on-chain activity found' };
    }
    
    return response.json();
  } catch (error) {
    throw error;
  }
}
{ 
  "detail": "Rate limit exceeded",
  "retry_after": 60
}
Causes:
  • Exceeded requests per minute limit
  • Exceeded monthly quota
Solutions:
  • Implement exponential backoff
  • Cache responses where possible
  • Upgrade your plan for higher limits
See Rate Limiting below.
{ "detail": "Internal server error" }
Causes:
  • Unexpected server-side error
  • Temporary system issue
Solutions:
  • Retry with exponential backoff
  • Contact support if the issue persists
  • Check status page for outages

Implementing Error Handling

Basic Error Handling

async function getScore(address) {
  const response = await fetch(
    `https://api.credprotocol.com/api/v2/score/${address}`,
    {
      headers: { 'Authorization': `Bearer ${API_KEY}` }
    }
  );

  if (!response.ok) {
    const error = await response.json();
    
    switch (response.status) {
      case 400:
        throw new Error(`Invalid request: ${error.detail}`);
      case 401:
        throw new Error('Authentication failed. Check your API key.');
      case 404:
        throw new Error('Address not found or has no activity.');
      case 429:
        throw new Error('Rate limit exceeded. Please try again later.');
      default:
        throw new Error(`API error: ${error.detail}`);
    }
  }

  return response.json();
}

With Retry Logic

async function fetchWithRetry(url, options, maxRetries = 3) {
  let lastError;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      // Don't retry client errors (except 429)
      if (response.status >= 400 && response.status < 500 && response.status !== 429) {
        const error = await response.json();
        throw new Error(error.detail);
      }
      
      // Retry on rate limit
      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After') || 60;
        await sleep(retryAfter * 1000);
        continue;
      }
      
      // Retry on server errors
      if (response.status >= 500) {
        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
        await sleep(delay);
        continue;
      }
      
      return response.json();
      
    } catch (error) {
      lastError = error;
      
      // Only retry on network errors
      if (error.name !== 'TypeError') throw error;
      
      const delay = Math.pow(2, attempt) * 1000;
      await sleep(delay);
    }
  }
  
  throw lastError;
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

Python Example

import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session():
    session = requests.Session()
    
    retries = Retry(
        total=3,
        backoff_factor=1,
        status_forcelist=[500, 502, 503, 504],
        allowed_methods=["GET"]
    )
    
    adapter = HTTPAdapter(max_retries=retries)
    session.mount("https://", adapter)
    
    return session

def get_score(address):
    session = create_session()
    
    response = session.get(
        f'https://api.credprotocol.com/api/v2/score/{address}',
        headers={'Authorization': f'Bearer {API_KEY}'}
    )
    
    if response.status_code == 429:
        retry_after = int(response.headers.get('Retry-After', 60))
        time.sleep(retry_after)
        return get_score(address)  # Retry once
    
    response.raise_for_status()
    return response.json()

Rate Limiting

Understanding Rate Limits

Rate limits are based on your plan:
PlanRequests/MinuteMonthly Quota
Free101,000
Growth10050,000
Pro1,000Unlimited

Handling Rate Limits

class RateLimitedClient {
  constructor(apiKey, requestsPerMinute = 10) {
    this.apiKey = apiKey;
    this.requestsPerMinute = requestsPerMinute;
    this.requestTimes = [];
  }

  async request(endpoint) {
    // Wait if we've hit the rate limit
    await this.waitForRateLimit();
    
    this.requestTimes.push(Date.now());
    
    const response = await fetch(
      `https://api.credprotocol.com${endpoint}`,
      {
        headers: { 'Authorization': `Bearer ${this.apiKey}` }
      }
    );
    
    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
      await this.sleep(retryAfter * 1000);
      return this.request(endpoint); // Retry
    }
    
    return response.json();
  }

  async waitForRateLimit() {
    const now = Date.now();
    const oneMinuteAgo = now - 60000;
    
    // Remove old request times
    this.requestTimes = this.requestTimes.filter(t => t > oneMinuteAgo);
    
    if (this.requestTimes.length >= this.requestsPerMinute) {
      const oldestRequest = this.requestTimes[0];
      const waitTime = oldestRequest + 60000 - now;
      await this.sleep(waitTime);
    }
  }

  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

Best Practices

Validate Input

Validate addresses and parameters before making API calls

Use Retries

Implement exponential backoff for transient errors

Cache Responses

Cache successful responses to reduce API calls

Log Errors

Log errors with context for debugging

Logging Example

async function getScore(address) {
  try {
    const data = await fetchScore(address);
    return data;
  } catch (error) {
    console.error('Cred API Error:', {
      address,
      error: error.message,
      timestamp: new Date().toISOString()
    });
    
    // Re-throw or handle gracefully
    throw error;
  }
}