Skip to main content

Error Types

ScriptBase errors fall into several categories:
  1. Authentication - Invalid/missing API key
  2. Validation - Invalid parameters
  3. Resource - Video/channel not found
  4. Rate Limiting - Too many requests
  5. Quota - Monthly limit exceeded
  6. Server - Internal errors
See Error Reference for complete error codes.

Basic Error Handling

async function safeApiCall(url: string, apiKey: string) {
  try {
    const response = await fetch(url, {
      headers: { 'X-API-Key': apiKey }
    });

    const data = await response.json();

    if (!data.success) {
      // Handle API error
      console.error(`API Error: ${data.error.code} - ${data.error.message}`);
      return null;
    }

    return data.data;
  } catch (error) {
    // Handle network error
    console.error('Network error:', error);
    return null;
  }
}

Handling Rate Limits

Implement exponential backoff for rate limit errors:
async function fetchWithRetry(
  url: string,
  apiKey: string,
  maxRetries = 3
) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, {
      headers: { 'X-API-Key': apiKey }
    });

    if (response.status === 429) {
      const retryAfter = parseInt(
        response.headers.get('Retry-After') || '60'
      );
      
      console.log(`Rate limited. Waiting ${retryAfter}s...`);
      await new Promise(resolve => 
        setTimeout(resolve, retryAfter * 1000)
      );
      continue;
    }

    return response.json();
  }

  throw new Error('Max retries exceeded');
}

Handling Quota Errors

if (error.code === 'QUOTA_EXCEEDED') {
  const resetDate = error.details.resetDate;
  console.error(`Quota exceeded. Resets on ${resetDate}`);
  
  // Options:
  // 1. Enable auto-recharge
  // 2. Upgrade plan
  // 3. Wait for reset
  // 4. Use cached data
}

Handling Missing Transcripts

Not all videos have transcripts:
async function getTranscriptSafely(videoId: string) {
  try {
    const response = await fetch(
      `https://api.scriptbase.app/api/v1/transcripts/${videoId}`,
      { headers: { 'X-API-Key': apiKey } }
    );
    
    const data = await response.json();
    
    if (data.error?.code === 'TRANSCRIPT_UNAVAILABLE') {
      console.log('No transcript available for this video');
      return null;
    }
    
    return data.data;
  } catch (error) {
    console.error('Failed to fetch transcript:', error);
    return null;
  }
}

Production-Ready Error Handler

class YTAPIClient {
  constructor(private apiKey: string) {}

  async request(endpoint: string, options = {}) {
    const maxRetries = 3;
    
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      try {
        const response = await fetch(
          `https://api.scriptbase.app${endpoint}`,
          {
            ...options,
            headers: {
              'X-API-Key': this.apiKey,
              ...options.headers
            }
          }
        );

        const data = await response.json();

        // Success
        if (data.success) {
          return data.data;
        }

        // Handle specific errors
        switch (data.error.code) {
          case 'RATE_LIMIT_EXCEEDED':
            if (attempt < maxRetries - 1) {
              const retryAfter = parseInt(
                response.headers.get('Retry-After') || '60'
              );
              await this.sleep(retryAfter * 1000);
              continue;
            }
            break;

          case 'QUOTA_EXCEEDED':
            throw new QuotaExceededError(data.error);

          case 'TRANSCRIPT_UNAVAILABLE':
            return null; // Expected for some videos

          case 'INVALID_API_KEY':
            throw new AuthError('Invalid API key');

          default:
            throw new APIError(data.error);
        }
      } catch (error) {
        if (attempt === maxRetries - 1) throw error;
        await this.sleep(1000 * Math.pow(2, attempt));
      }
    }
  }

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