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.
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:
| Tier | Rate Limit | Monthly Calls | Overage |
|---|---|---|---|
| Free | 30 requests/minute | 2,000 | Hard limit |
| Pro | 60 requests/minute | 10,000 | $0.005/call |
| Scale | 120 requests/minute | 100,000 | $0.003/call |
| Enterprise | Custom | Custom | Custom |
Rate limit headers are included in every response:
| Header | Description |
|---|---|
X-RateLimit-Limit | Requests allowed per minute |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Seconds until the rate limit window resets |
Retry-After | Seconds to wait before retrying (only on 429) |
Error Response Format
All errors follow the same envelope format:
{
"detail": {
"error": "rate_limit_exceeded",
"message": "Rate limit: 60 requests/minute"
}
}
Common Error Codes
| Status | Error | Description |
|---|---|---|
401 | missing_api_key | No API key provided in request headers |
401 | invalid_api_key | The API key is not recognized |
401 | api_key_revoked | The API key has been deactivated |
422 | Validation error | Request body doesn't match expected schema |
429 | rate_limit_exceeded | Too many requests — check Retry-After header |
500 | Internal server error | Something 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}")