Skip to main content
This guide covers all aspects of error handling when working with the DRIP API, including common error scenarios, proper error handling techniques, and troubleshooting steps.

Error Response Format

All DRIP API errors follow a consistent format:
{
  "error": "ValidationError",
  "message": "Invalid request parameters",
  "details": {
    "field": "tokens",
    "issue": "Must be a positive integer"
  },
  "requestId": "req_1234567890abcdef",
  "timestamp": "2024-01-20T15:30:00Z"
}

Error Response Fields

FieldDescription
errorError type identifier
messageHuman-readable error description
detailsAdditional error context (when available)
requestIdUnique request identifier for support
timestampWhen the error occurred

HTTP Status Codes

The DRIP API uses standard HTTP status codes:

2xx Success

  • 200 OK: Request successful
  • 201 Created: Resource created successfully
  • 204 No Content: Request successful, no response body

4xx Client Errors

  • 400 Bad Request: Invalid request format or parameters
  • 401 Unauthorized: Missing or invalid authentication
  • 403 Forbidden: Valid authentication but insufficient permissions
  • 404 Not Found: Requested resource doesn’t exist
  • 409 Conflict: Request conflicts with current resource state
  • 422 Unprocessable Entity: Valid format but business logic error
  • 429 Too Many Requests: Rate limit exceeded

5xx Server Errors

  • 500 Internal Server Error: Unexpected server error
  • 502 Bad Gateway: Upstream service error
  • 503 Service Unavailable: Temporary service outage
  • 504 Gateway Timeout: Upstream service timeout

Common Error Types

Authentication Errors

{
  "error": "Unauthorized",
  "message": "Invalid API key provided"
}
Causes:
  • API key is incorrect or malformed
  • API key has been revoked
  • Missing Authorization header
Solutions:
  • Verify your API key is correct
  • Generate a new API key if needed
  • Ensure proper header format: Authorization: Bearer YOUR_KEY
{
  "error": "Forbidden",
  "message": "Insufficient permissions to access this resource"
}
Causes:
  • API key lacks required permissions
  • Trying to access another realm’s resources
  • Account permissions have been changed
Solutions:
  • Check your account permissions in the dashboard
  • Ensure you’re using the correct realm ID
  • Contact an admin to update permissions

Validation Errors

{
  "error": "ValidationError",
  "message": "Invalid request parameters",
  "details": {
    "tokens": "Must be a number between -1000000 and 1000000",
    "realmPointId": "Must be a valid ObjectId"
  }
}
Common Issues:
  • Invalid data types (string instead of number)
  • Missing required fields
  • Values outside allowed ranges
  • Malformed IDs
Solutions:
  • Validate input data before sending requests
  • Check API documentation for required fields and formats
  • Use proper data types in your requests
{
  "error": "InsufficientBalance",
  "message": "Member does not have enough points for this operation",
  "details": {
    "currentBalance": 50,
    "requestedAmount": 100,
    "memberId": "507f1f77bcf86cd799439013"
  }
}
Common Scenarios:
  • Insufficient point balance for transfers
  • Duplicate resource creation
  • Quest already completed
  • Store item out of stock
Solutions:
  • Check resource state before operations
  • Implement proper business logic validation
  • Handle edge cases gracefully

Resource Errors

{
  "error": "NotFound",
  "message": "Realm member not found",
  "details": {
    "realmId": "507f1f77bcf86cd799439011",
    "memberId": "507f1f77bcf86cd799439013"
  }
}
Common Causes:
  • Incorrect resource IDs
  • Resource has been deleted
  • Member hasn’t joined the realm
  • Typos in endpoint URLs
Solutions:
  • Verify resource IDs are correct
  • Check if resources exist before operations
  • Handle missing resources gracefully
{
  "error": "ConflictError",
  "message": "Quest is already completed and cannot be modified",
  "details": {
    "questId": "507f1f77bcf86cd799439015",
    "currentStatus": "completed"
  }
}
Common Scenarios:
  • Modifying completed quests
  • Creating duplicate resources
  • Concurrent modification conflicts
Solutions:
  • Check resource state before modifications
  • Implement proper concurrency handling
  • Use appropriate HTTP methods (PUT vs PATCH)

Rate Limiting Errors

{
  "error": "RateLimitExceeded",
  "message": "Too many requests. Try again in 60 seconds.",
  "details": {
    "limit": 100,
    "window": 60,
    "retryAfter": 60
  }
}
Solutions:
  • Implement exponential backoff
  • Respect the Retry-After header
  • Use batch operations when possible
  • See the Rate Limits guide for details

Error Handling Implementation

JavaScript/Node.js

class DripAPIError extends Error {
  constructor(status, error, message, details, requestId) {
    super(message);
    this.name = 'DripAPIError';
    this.status = status;
    this.error = error;
    this.details = details;
    this.requestId = requestId;
  }
}

class DripClient {
  async request(method, endpoint, data = null) {
    try {
      const response = await fetch(`${this.baseUrl}${endpoint}`, {
        method,
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json'
        },
        body: data ? JSON.stringify(data) : null
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new DripAPIError(
          response.status,
          errorData.error,
          errorData.message,
          errorData.details,
          errorData.requestId
        );
      }

      return response.json();
    } catch (error) {
      if (error instanceof DripAPIError) {
        throw error;
      }
      
      // Handle network errors, JSON parsing errors, etc.
      throw new Error(`Network error: ${error.message}`);
    }
  }

  async safeRequest(method, endpoint, data = null, options = {}) {
    const { retries = 3, retryDelay = 1000 } = options;
    
    for (let attempt = 0; attempt <= retries; attempt++) {
      try {
        return await this.request(method, endpoint, data);
      } catch (error) {
        if (error instanceof DripAPIError) {
          // Don't retry client errors (4xx) except rate limits
          if (error.status >= 400 && error.status < 500 && error.status !== 429) {
            throw error;
          }
          
          // Handle rate limits
          if (error.status === 429) {
            const retryAfter = error.details?.retryAfter || 60;
            if (attempt < retries) {
              await this.sleep(retryAfter * 1000);
              continue;
            }
          }
          
          // Retry server errors (5xx)
          if (error.status >= 500 && attempt < retries) {
            await this.sleep(retryDelay * Math.pow(2, attempt));
            continue;
          }
        }
        
        // Final attempt or non-retryable error
        if (attempt === retries) {
          throw error;
        }
      }
    }
  }

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

Python

import requests
import time
from typing import Optional, Dict, Any

class DripAPIError(Exception):
    def __init__(self, status: int, error: str, message: str, details: Optional[Dict] = None, request_id: Optional[str] = None):
        super().__init__(message)
        self.status = status
        self.error = error
        self.message = message
        self.details = details or {}
        self.request_id = request_id

class DripClient:
    def __init__(self, api_key: str, realm_id: str):
        self.api_key = api_key
        self.realm_id = realm_id
        self.base_url = 'https://api.drip.re/api/v1'
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        })

    def request(self, method: str, endpoint: str, data: Optional[Dict] = None) -> Dict[Any, Any]:
        try:
            response = self.session.request(method, f"{self.base_url}{endpoint}", json=data)
            
            if not response.ok:
                try:
                    error_data = response.json()
                except ValueError:
                    error_data = {'error': 'UnknownError', 'message': 'Unknown error occurred'}
                
                raise DripAPIError(
                    status=response.status_code,
                    error=error_data.get('error', 'UnknownError'),
                    message=error_data.get('message', 'Unknown error'),
                    details=error_data.get('details'),
                    request_id=error_data.get('requestId')
                )
            
            return response.json()
            
        except requests.exceptions.RequestException as e:
            raise Exception(f"Network error: {str(e)}")

    def safe_request(self, method: str, endpoint: str, data: Optional[Dict] = None, retries: int = 3, retry_delay: int = 1) -> Dict[Any, Any]:
        for attempt in range(retries + 1):
            try:
                return self.request(method, endpoint, data)
                
            except DripAPIError as e:
                # Don't retry client errors except rate limits
                if 400 <= e.status < 500 and e.status != 429:
                    raise e
                
                # Handle rate limits
                if e.status == 429:
                    retry_after = e.details.get('retryAfter', 60)
                    if attempt < retries:
                        time.sleep(retry_after)
                        continue
                
                # Retry server errors
                if e.status >= 500 and attempt < retries:
                    time.sleep(retry_delay * (2 ** attempt))
                    continue
                
                # Final attempt
                if attempt == retries:
                    raise e
                    
            except Exception as e:
                if attempt == retries:
                    raise e
                time.sleep(retry_delay * (2 ** attempt))

Debugging and Troubleshooting

Request ID Tracking

Always log the requestId from error responses for support:
function logError(error) {
  if (error instanceof DripAPIError) {
    console.error(`[${error.requestId}] ${error.error}: ${error.message}`);
    if (error.details) {
      console.error('Details:', JSON.stringify(error.details, null, 2));
    }
  }
}

Common Debugging Steps

1

Verify API Key

Test your API key with a simple request:
curl -X GET "https://api.drip.re/api/v1/realms/YOUR_REALM_ID" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -w "\nStatus: %{http_code}\n"
2

Check Request Format

Ensure your request matches the API documentation:
  • Correct HTTP method
  • Proper JSON format
  • Required headers included
  • Valid parameter types
3

Validate Resource IDs

Confirm that all IDs in your request are valid:
  • Realm ID exists and you have access
  • Member ID exists in the realm
  • Point type ID is correct
4

Test with cURL

Replicate the failing request with cURL to isolate the issue:
curl -X PATCH "https://api.drip.re/api/v1/realm/REALM_ID/members/MEMBER_ID/point-balance" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tokens": 100}' \
  -v

Error Monitoring

Set up monitoring to track error patterns:
class ErrorMonitor {
  constructor() {
    this.errors = [];
  }

  recordError(error, context = {}) {
    this.errors.push({
      timestamp: new Date().toISOString(),
      status: error.status,
      error: error.error,
      message: error.message,
      requestId: error.requestId,
      context
    });

    // Alert on high error rates
    this.checkErrorRate();
  }

  checkErrorRate() {
    const recentErrors = this.errors.filter(
      e => Date.now() - new Date(e.timestamp).getTime() < 300000 // Last 5 minutes
    );

    if (recentErrors.length > 10) {
      console.warn('High error rate detected:', recentErrors.length, 'errors in 5 minutes');
      // Send alert to monitoring system
    }
  }

  getErrorStats() {
    const last24h = this.errors.filter(
      e => Date.now() - new Date(e.timestamp).getTime() < 86400000
    );

    const errorCounts = last24h.reduce((acc, error) => {
      acc[error.error] = (acc[error.error] || 0) + 1;
      return acc;
    }, {});

    return {
      total: last24h.length,
      byType: errorCounts,
      recent: last24h.slice(-10)
    };
  }
}

Best Practices

Graceful Degradation

  • Always handle errors gracefully
  • Provide meaningful user feedback
  • Implement fallback behaviors
  • Log errors for debugging

Retry Logic

  • Implement exponential backoff
  • Don’t retry client errors (4xx)
  • Respect rate limit headers
  • Set maximum retry limits

Error Logging

  • Log all API errors with context
  • Include request IDs for support
  • Monitor error patterns
  • Set up alerting for high error rates

User Experience

  • Show user-friendly error messages
  • Provide actionable next steps
  • Handle loading and error states
  • Implement proper error boundaries

Getting Help

When contacting support about API errors:
  1. Include the Request ID from the error response
  2. Provide the full error response with status code
  3. Share your request details (without sensitive data)
  4. Describe the expected behavior vs what happened
  5. Include relevant logs and timestamps