Skip to main content

Error Handling

This guide provides information about error responses from the BitPulse API and how to handle them.

Error Codes

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

Status CodeDescription
400 Bad RequestThe request was malformed or missing required parameters.
401 UnauthorizedThe API key provided was invalid or missing.
404 Not FoundThe requested resource was not found.
500 Internal Server ErrorAn unexpected error occurred on the server.

Error Response Format

When an error occurs, the API returns a JSON response with details about the error:

{
"error": {
"code": "unauthorized",
"message": "Invalid API key provided",
"details": "The API key in the x-api-key header is invalid or expired"
}
}

Common Error Scenarios

Authentication Errors

Status Code: 401 Unauthorized

This error occurs when:

  • No API key is provided in the x-api-key header
  • The API key is invalid or has expired
  • The API key doesn't have permission to access the requested resource

Example:

{
"error": {
"code": "unauthorized",
"message": "Invalid API key provided",
"details": "The API key in the x-api-key header is invalid or expired"
}
}

Invalid Request Errors

Status Code: 400 Bad Request

This error occurs when:

  • Required parameters are missing
  • Parameters have invalid values
  • The request body is malformed

Missing Required Parameters

Example: Missing required collateral_weights in loan risk calculation

{
"error": {
"code": "invalid_request",
"message": "Missing required parameter",
"details": "The 'collateral_weights' field is required for risk assessment"
}
}

Invalid Parameter Values

Example: Invalid model type for VaR calculation

{
"error": {
"code": "invalid_parameter",
"message": "Invalid parameter value",
"details": "The 'type' parameter must be one of: 'GBM'"
}
}

Parameter Range Errors

Example: Value outside allowed range in perpetual futures risk calculation

{
"error": {
"code": "parameter_range_error",
"message": "Parameter value out of range",
"details": "The 'funding_rate' parameter must be between -0.999999 and 0.999999"
}
}

Schema Validation Errors

Example: Invalid structure in loan origination request

{
"error": {
"code": "schema_validation_error",
"message": "Request schema validation failed",
"details": "The 'opt_param' object must contain 'variable_min', 'variable_max', and 'score_target' properties"
}
}

Forbidden Errors

Status Code: 403 Forbidden

This error occurs when:

  • The API key doesn't have permission to access a specific endpoint
  • The user has exceeded their rate limit or quota

Example:

{
"error": {
"code": "forbidden",
"message": "Access denied",
"details": "Your API key doesn't have permission to access the '/isolated_perp_risk' endpoint"
}
}

Resource Not Found Errors

Status Code: 404 Not Found

This error occurs when:

  • The requested endpoint doesn't exist
  • The requested resource doesn't exist

Example:

{
"error": {
"code": "not_found",
"message": "Resource not found",
"details": "The requested endpoint '/invalid_endpoint' does not exist"
}
}

Server Errors

Status Code: 500 Internal Server Error

This error occurs when:

  • An unexpected error occurs on the server
  • The server is temporarily unavailable
  • Calculation errors in the risk models

Example: Generic server error

{
"error": {
"code": "server_error",
"message": "Internal server error",
"details": "An unexpected error occurred while processing your request"
}
}

Example: Calculation error

{
"error": {
"code": "calculation_error",
"message": "Risk model calculation failed",
"details": "Unable to compute risk metrics with the provided parameters"
}
}

Endpoint-Specific Error Examples

Loan Risk Endpoint Errors

The /loan_risk endpoint may return these specific errors:

{
"error": {
"code": "invalid_parameter",
"message": "Invalid model type",
"details": "The 'type' parameter must be one of: 'GBM', 'GBM_VIX', 'HISTORICAL', 'BETA_GARCH'"
}
}
{
"error": {
"code": "missing_parameter",
"message": "Missing required parameter",
"details": "The 'collateral_weights' object is required for risk calculation"
}
}

Loan Origination Endpoint Errors

The /loan_origination endpoint may return these specific errors:

{
"error": {
"code": "invalid_parameter",
"message": "Invalid optimization parameters",
"details": "The 'opt_param' object must include 'score_target' and 'score_variable' fields"
}
}
{
"error": {
"code": "parameter_range_error",
"message": "Invalid parameter range",
"details": "The 'variable_min' must be less than 'variable_max' in opt_param"
}
}

VaR Endpoint Errors

The /var endpoint may return these specific errors:

{
"error": {
"code": "invalid_parameter",
"message": "Invalid parameter format",
"details": "The 'quantile' parameter must be an array of numbers between 0 and 1"
}
}
{
"error": {
"code": "calculation_error",
"message": "VaR calculation failed",
"details": "Unable to calculate VaR with the provided parameters"
}
}

Isolated Perpetual Futures Risk Endpoint Errors

The /isolated_perp_risk endpoint may return these specific errors:

{
"error": {
"code": "invalid_parameter",
"message": "Invalid contract type",
"details": "The 'contract_type' parameter must be one of: 'linear', 'inverse'"
}
}
{
"error": {
"code": "missing_parameter",
"message": "Missing required parameter",
"details": "For inverse contracts, 'contract_value_usd' is required"
}
}
{
"error": {
"code": "parameter_range_error",
"message": "Invalid parameter value",
"details": "The 'model_lookback' must be between 1 and 1000 days"
}
}

Error Handling Best Practices

  1. Always check status codes: Before processing the response, check the HTTP status code to determine if the request was successful.

  2. Implement retry logic: For transient errors (like network issues or temporary server unavailability), implement retry logic with exponential backoff.

  3. Log error details: Log the complete error response for debugging purposes.

  4. Handle specific error cases: Implement specific handling for different error types (authentication errors, validation errors, etc.).

  5. Display user-friendly messages: When showing errors to end users, translate technical error messages into user-friendly language.

Example Error Handling (Python)

import requests
import time
import json
import logging

# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('bitpulse_api')

class BitPulseApiError(Exception):
"""Custom exception for BitPulse API errors"""
def __init__(self, code, message, details=None, status_code=None):
self.code = code
self.message = message
self.details = details
self.status_code = status_code
super().__init__(f"{message}: {details}")

def make_api_request(endpoint, payload, api_key, max_retries=3):
"""
Make a request to the BitPulse API with error handling and retries

Args:
endpoint (str): API endpoint (e.g., '/loan_risk')
payload (dict): Request payload
api_key (str): Your API key
max_retries (int): Maximum number of retry attempts

Returns:
dict: API response data

Raises:
BitPulseApiError: For API-specific errors
requests.exceptions.RequestException: For network-related errors
"""
uri = "https://api-staging.riskstudio.io" # Use production URL in production
headers = {
"Content-type": "application/json",
"x-api-key": api_key,
}

retry_count = 0
while retry_count < max_retries:
try:
logger.info(f"Making request to {endpoint}")
response = requests.post(
uri + endpoint,
data=json.dumps(payload),
headers=headers
)

# Check if request was successful
if response.status_code == 200:
logger.info(f"Request to {endpoint} successful")
return response.json()

# Parse error response
try:
error_data = response.json().get('error', {})
error_code = error_data.get('code', 'unknown_error')
error_message = error_data.get('message', 'Unknown error occurred')
error_details = error_data.get('details', 'No additional details')
except (ValueError, KeyError):
error_code = 'parse_error'
error_message = 'Failed to parse error response'
error_details = response.text[:100] + '...' if len(response.text) > 100 else response.text

# Handle specific error cases
if response.status_code == 401:
logger.error(f"Authentication error: {error_message}")
raise BitPulseApiError(error_code, error_message, error_details, response.status_code)

elif response.status_code == 403:
logger.error(f"Authorization error: {error_message}")
raise BitPulseApiError(error_code, error_message, error_details, response.status_code)

elif response.status_code == 400:
logger.error(f"Bad request: {error_message} - {error_details}")

# Handle specific validation errors
if error_code == 'invalid_parameter' and 'type' in error_details:
logger.error("Invalid model type specified")
elif error_code == 'missing_parameter':
logger.error(f"Missing required parameter: {error_details}")
elif error_code == 'parameter_range_error':
logger.error(f"Parameter value out of allowed range: {error_details}")

raise BitPulseApiError(error_code, error_message, error_details, response.status_code)

elif response.status_code == 404:
logger.error(f"Resource not found: {error_message}")
raise BitPulseApiError(error_code, error_message, error_details, response.status_code)

# For server errors, retry with exponential backoff
elif response.status_code == 500:
retry_count += 1
if retry_count < max_retries:
wait_time = 2 ** retry_count # Exponential backoff
logger.warning(f"Server error. Retrying in {wait_time} seconds...")
time.sleep(wait_time)
else:
logger.error(f"Maximum retries reached. Server error: {error_message}")
raise BitPulseApiError(error_code, error_message, error_details, response.status_code)

# Handle other status codes
else:
logger.error(f"Unexpected status code {response.status_code}: {error_message}")
raise BitPulseApiError(error_code, error_message, error_details, response.status_code)

except requests.exceptions.RequestException as e:
retry_count += 1
if retry_count < max_retries:
wait_time = 2 ** retry_count
logger.warning(f"Network error: {e}. Retrying in {wait_time} seconds...")
time.sleep(wait_time)
else:
logger.error(f"Maximum retries reached. Network error: {e}")
raise

# Example usage
def calculate_loan_risk(api_key, collateral_weights, loan_weights, loan_value):
"""
Calculate loan risk metrics

Args:
api_key (str): Your API key
collateral_weights (dict): Collateral asset weights (e.g., {"BTC": 0.8, "ETH": 0.2})
loan_weights (dict): Loan asset weights (e.g., {"USDC": 1.0})
loan_value (float): Loan value

Returns:
dict: Risk assessment results
"""
try:
payload = {
"type": "GBM",
"params": {
"collateral_weights": collateral_weights,
"loan_weights": loan_weights,
"loan_value": loan_value,
"N": 1.5,
"M": 1.2,
"L": 0.7,
"R": 0.05,
"model_lookback": 90,
"loan_duration": 30,
"mc_top_up": 0.05,
"mc_iter": 10000
}
}

return make_api_request("/loan_risk", payload, api_key)

except BitPulseApiError as e:
logger.error(f"API error: {e.code} - {e.message}")
if e.code == "missing_parameter":
logger.info("Please check that all required parameters are provided")
elif e.code == "invalid_parameter":
logger.info("Please check the format and values of your parameters")
return {"error": {"code": e.code, "message": e.message, "details": e.details}}

except requests.exceptions.RequestException as e:
logger.error(f"Network error: {str(e)}")
return {"error": {"code": "network_error", "message": "Network connection failed", "details": str(e)}}

Getting Help

If you encounter persistent errors or need assistance with error handling, please contact our support team at support@bitpulse.io.