Python SDK & Reference

A lightweight Python client for the REST API with typed exceptions and clean error handling.

Installation

pip install koko-finance

Requires Python 3.8+. The only dependency is requests.

GitHub Repository →    PyPI →

Usage Examples

from koko_finance import KokoClient

client = KokoClient(api_key="YOUR_API_KEY")

# Analyze your credit card portfolio
analysis = client.analyze_portfolio(
    cards=[
        {"card_name": "Chase Sapphire Preferred", "annual_fee": 95},
        {"card_name": "American Express Gold Card", "annual_fee": 250},
        {"card_name": "Citi Double Cash", "annual_fee": 0},
    ],
    spending={"dining": 500, "travel": 300, "groceries": 600, "gas": 150},
    primary_goal="travel",
)

# Compare two cards head-to-head
comparison = client.compare_cards(
    cards=[
        {"card_name": "Chase Sapphire Preferred", "annual_fee": 95},
        {"card_name": "Capital One Venture X", "annual_fee": 395},
    ],
    spending={"dining": 400, "travel": 500},
    primary_goal="travel",
    credit_tier="excellent",
    benefit_selections=["dining", "travel"],
)

# Get recommendation for a spending category
recs = client.recommend_card(
    category="dining",
    spending={"dining": 600},
    credit_tier="excellent",
)

# Check if a card is worth renewing
renewal = client.check_renewal(
    card={"card_name": "Chase Sapphire Preferred", "annual_fee": 95},
    spending={"dining": 400, "travel": 300},
    credit_tier="excellent",
    acquired_date="2024-06-15",
)

# Get detailed info about a specific card
details = client.get_card_details(card_name="Chase Sapphire Preferred")

# Calculate card value based on your spending
value = client.calculate_card_value(
    card_name="Chase Sapphire Preferred",
    spending={"dining": 500, "travel": 300, "groceries": 400},
    benefit_selections=["dining", "travel"],
)

# Get card terms by name (fuzzy matching)
terms = client.get_card_terms(card_name="Chase Sapphire Preferred")

# Get card history by name (fuzzy matching)
history = client.get_card_history(
    card_name="Chase Sapphire Preferred",
    since="2026-01-01",
)

# Merchant Intelligence: best card at a merchant
best = client.which_card_at_merchant(
    merchant="Starbucks",
    amount=35,
    portfolio=["Chase Sapphire Reserve", "Amex Gold", "Citi Double Cash"],
)

# Check card credits at a merchant
benefits = client.merchant_benefits(
    merchant="Saks Fifth Avenue",
    portfolio=["Amex Platinum", "Chase Sapphire Reserve"],
)

# Get all credits/benefits for a card
card_info = client.card_benefits(card="Amex Platinum")

Rate Limits

All authenticated endpoints are rate-limited. Current limits:

TierRate LimitMonthly CallsOverage
Free30 requests/minute2,000Hard limit
Pro60 requests/minute10,000$0.005/call
Scale120 requests/minute100,000$0.003/call
EnterpriseCustomCustomCustom

Rate limit headers are included in every response:

HeaderDescription
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetSeconds until the rate limit window resets
Retry-AfterSeconds to wait before retrying (only on 429)

View pricing and rate limits →

Error Response Format

All errors follow the same envelope format:

{
  "detail": {
    "error": "rate_limit_exceeded",
    "message": "Rate limit: 60 requests/minute"
  }
}

Common Error Codes

StatusErrorDescription
401missing_api_keyNo API key provided in request headers
401invalid_api_keyThe API key is not recognized
401api_key_revokedThe API key has been deactivated
422Validation errorRequest body doesn't match expected schema
429rate_limit_exceededToo many requests — check Retry-After header
500Internal server errorSomething went wrong on our end

Python SDK Exception Handling

from koko_finance import KokoClient, RateLimitError, AuthenticationError, ValidationError

client = KokoClient(api_key="YOUR_API_KEY")

try:
    result = client.analyze_portfolio(cards=[...])
except AuthenticationError:
    print("Invalid or missing API key")
except RateLimitError as e:
    print(f"Rate limited — retry after {e.retry_after}s")
except ValidationError as e:
    print(f"Bad request: {e.message}")