Skip to main content

Error Response Format

All errors return a consistent structure:
{
  "status": "failed",
  "msg": "Invalid password for PDF",
  "code": "INVALID_PASSWORD"
}

HTTP Status Codes

StatusMeaningRetry?
200SuccessN/A
400Bad requestNo — fix request
401Invalid API keyNo — check credentials
402Insufficient creditsNo — upgrade plan
422Invalid PDF/passwordNo — check inputs
429Rate limitedYes — exponential backoff
500Server errorYes — retry with backoff
502/503Service unavailableYes — retry with backoff

Error Codes

Client Errors (4xx)

CodeHTTPDescriptionSolution
INVALID_API_KEY401API key missing or invalidCheck x-api-key header
INSUFFICIENT_CREDITS402No credits remainingUpgrade plan or wait for reset
INVALID_PASSWORD422Wrong PDF passwordVerify PAN format for CDSL/NSDL
INVALID_PDF422Corrupted or scanned PDFUse original digital PDF
UNSUPPORTED_FORMAT422Not a CAS fileUpload CAS, not bank statement
FILE_TOO_LARGE422PDF exceeds 10MBCompress or split PDF
RATE_LIMITED429Too many requestsWait 60s or implement backoff

Server Errors (5xx)

CodeHTTPDescriptionSolution
PARSING_ERROR500Internal parsing failureRetry or contact support
TIMEOUT504Request took too longRetry with longer timeout

Retry Logic

When to Retry

Retry these errors:
  • 429 (Rate Limited)
  • 500 (Server Error)
  • 502/503 (Service Unavailable)
  • 504 (Timeout)
Don’t retry these:
  • 400 (Bad Request)
  • 401 (Invalid API Key)
  • 402 (Insufficient Credits)
  • 422 (Invalid PDF/Password)

Exponential Backoff

import requests
import time

def parse_with_retry(file_path, password, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(
                "https://api.casparser.in/v4/smart/parse",
                headers={"x-api-key": API_KEY},
                files={"file": open(file_path, "rb")},
                data={"password": password},
                timeout=60
            )
            
            # Don't retry client errors
            if 400 <= response.status_code < 500 and response.status_code != 429:
                response.raise_for_status()
            
            # Retry server errors and rate limits
            if response.status_code >= 500 or response.status_code == 429:
                if attempt < max_retries - 1:
                    wait_time = 2 ** attempt  # 1s, 2s, 4s
                    time.sleep(wait_time)
                    continue
                response.raise_for_status()
            
            return response.json()
            
        except requests.exceptions.Timeout:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)
                continue
            raise
    
    raise Exception("Max retries exceeded")

Timeout Configuration

OperationRecommended Timeout
CAS parsing60 seconds
CDSL fetch (Step 1)50 seconds
CDSL fetch (Step 2)10 seconds
Credits check5 seconds
Token generation5 seconds
CDSL fetch Step 1 takes 15-20 seconds due to automated captcha solving. Set timeout to at least 50s.

Graceful Degradation

def parse_cas_safe(file_path, password):
    """Parse CAS with graceful error handling."""
    try:
        response = requests.post(
            "https://api.casparser.in/v4/smart/parse",
            headers={"x-api-key": API_KEY},
            files={"file": open(file_path, "rb")},
            data={"password": password},
            timeout=60
        )
        
        data = response.json()
        
        if data.get("status") == "failed":
            error_code = data.get("code", "UNKNOWN")
            
            if error_code == "INVALID_PASSWORD":
                return {
                    "error": "Wrong password. Please check your CAS email for the correct password.",
                    "retry": False
                }
            elif error_code == "INVALID_PDF":
                return {
                    "error": "Invalid PDF. Please upload the original digital PDF, not a scanned copy.",
                    "retry": False
                }
            elif error_code == "INSUFFICIENT_CREDITS":
                return {
                    "error": "No credits remaining. Please upgrade your plan.",
                    "retry": False,
                    "upgrade_url": "https://app.casparser.in/billing"
                }
            else:
                return {
                    "error": f"Parsing failed: {data.get('msg')}",
                    "retry": True
                }
        
        return {"success": True, "data": data}
        
    except requests.exceptions.Timeout:
        return {
            "error": "Request timed out. The PDF may be too large or complex.",
            "retry": True
        }
    except requests.exceptions.ConnectionError:
        return {
            "error": "Network error. Please check your internet connection.",
            "retry": True
        }
    except Exception as e:
        return {
            "error": f"Unexpected error: {str(e)}",
            "retry": False
        }

Request Tracing

Every response includes an X-Request-ID header:
response = requests.post(...)
request_id = response.headers.get("X-Request-ID")
print(f"Request ID: {request_id}")  # req_2xYz7KpL8mN3Ab
Include this ID when contacting support for faster resolution.

Monitoring & Alerts

Track Error Rates

import logging

def parse_with_logging(file_path, password):
    request_id = None
    try:
        response = requests.post(...)
        request_id = response.headers.get("X-Request-ID")
        
        data = response.json()
        if data.get("status") == "failed":
            logging.error(f"Parsing failed: {data.get('msg')} (Request ID: {request_id})")
        
        return data
    except Exception as e:
        logging.error(f"Exception: {str(e)} (Request ID: {request_id})")
        raise

Set Up Alerts

Monitor these metrics:
  • Error rate — Alert if greater than 5% of requests fail
  • Timeout rate — Alert if greater than 2% timeout
  • Credit balance — Alert when less than 10 credits remain

Next Steps