REST API Reference

22 endpoints for credit card intelligence. All responses follow a consistent envelope: { success, data, metadata, error }.

Authentication

All endpoints (except /health) require an API key passed via the X-API-Key header:

X-API-Key: koko_your_api_key

Base URL

https://kokofinance.net/api/v1

Try it interactively in Swagger UI →

Fast vs Verbose Endpoints

Four endpoints offer both a fast (default) and verbose variant:

EndpointFast (default)Verbose
/portfolio/analyze Deterministic calculations, <100ms /portfolio/analyze/verbose — adds AI narrative (3-5s)
/cards/compare Side-by-side data, <100ms /cards/compare/verbose — adds AI winner & pros/cons (3-5s)
/cards/recommend Deterministic ranking, <100ms /cards/recommend/verbose — adds AI headline & explanation (2-4s)
/card/renewal-check Deterministic verdict, <100ms /card/renewal-check/verbose — adds retention tips & timing guidance (3-5s)

The metadata.mode field in every response tells you which variant was used: "fast" or "verbose".

Response Metadata Fields

Calculation endpoints (/portfolio/analyze, /cards/compare, /card/renewal-check, /cards/value) include these fields in their responses:

FieldTypeDescription
spending_sourcestring"user_provided" or "national_averages" — indicates whether calculations used your spending data or BLS national averages
points_program_keystringProgram key (e.g. "chase_ur", "amex_mr") linking the card to its points program
portal_cppnumberPortal cents-per-point redemption value (e.g. 1.25 for Chase UR via travel portal)
rewards_by_categoryobjectPer-category reward breakdown showing how value was calculated

Portfolio Analysis

POST /portfolio/analyze

Analyze 1-10 credit cards for total value, per-card verdicts (KEEP/OPTIMIZE/CANCEL), and break-even analysis. Fast deterministic endpoint (<100ms). Use /portfolio/analyze/verbose for AI-generated narrative.

FieldTypeRequiredDescription
cardsarrayYes1-10 cards, each with card_name and optional annual_fee
params.spendingobjectNoMonthly spending by category (dining, travel, groceries, gas, streaming, shopping, other)
params.primary_goalstringNotravel, cashback, build_credit, business, or balance_transfer
params.credit_tierstringNopoor, fair, good, or excellent
params.issuer_preferencesarrayNoBoost/de-boost issuers, e.g. [{"issuer": "Chase", "weight": 1.5}]
params.point_balancesarrayNoYour rewards balances, e.g. [{"program": "chase_ur", "balance": 150000}]. Enriches analysis with redemption context.
params.benefit_selectionsarrayNoIndividual benefit keys the user actually uses (e.g. ["uber", "dining", "admirals_club"]). Selected benefits count at 100%; unselected at 0%. If omitted, 50% default utilization is assumed.
Request
{
  "cards": [
    {"card_name": "Chase Sapphire Preferred", "annual_fee": 95},
    {"card_name": "American Express Gold Card", "annual_fee": 250}
  ],
  "params": {
    "spending": {
      "dining": 500, "travel": 300,
      "groceries": 400, "gas": 100,
      "streaming": 30, "shopping": 200,
      "other": 150
    },
    "primary_goal": "travel",
    "point_balances": [
      {"program": "chase_ur", "balance": 150000},
      {"program": "amex_mr", "balance": 80000}
    ],
    "benefit_selections": ["uber", "dining", "travel", "saks"]
  }
}
Response
{
  "success": true,
  "data": {
    "card_details": [
      {
        "card_name": "Chase Sapphire Preferred",
        "net_value": 188,
        "verdict": "keep",
        "points_program_key": "chase_ur",
        "portal_cpp": 1.25,
        "rewards_by_category": {"dining": 180, "travel": 72, ...},
        "break_even": {"status": "spending_required"}
      },
      ...
    ],
    "portfolio_summary": {
      "total_annual_fees": 345,
      "net_value": 434,
      "total_rewards": 444
    },
    "spending_source": "user_provided",
    "assumptions": {"redemption_rate": 1.0, "point_value": 0.01}
  },
  "metadata": {
    "request_id": "a1b2c3d4e5f6",
    "api_version": "v1",
    "latency_ms": 52,
    "mode": "fast",
    "timestamp": "2026-03-11T14:30:00Z"
  },
  "error": null
}

Card Comparison

POST /cards/compare

Compare 2-3 credit cards side-by-side with fees, rewards, net value, and break-even analysis. Fast deterministic endpoint (<100ms). Use /cards/compare/verbose for AI-generated winner and narrative.

FieldTypeRequiredDescription
card_namesarray[string]Yes2-3 card names to compare
params.spendingobjectNoMonthly spending by category
params.primary_goalstringNoOptimization goal
params.credit_tierstringNopoor, fair, good, or excellent — affects eligibility filtering
params.benefit_selectionsarrayNoBenefit keys the user uses (100%/0% model). See /benefit-categories for valid keys.
Request
{
  "card_names": [
    "Chase Sapphire Preferred",
    "Capital One Venture X"
  ],
  "params": {
    "spending": {"dining": 400, "travel": 500, "groceries": 300},
    "primary_goal": "travel",
    "credit_tier": "excellent",
    "benefit_selections": ["travel", "dining"]
  }
}
Response
{
  "success": true,
  "data": {
    "comparison_table": [
      {
        "card_name": "Chase Sapphire Preferred",
        "annual_fee": 95,
        "net_value": 188,
        "total_rewards": 198,
        "points_program_key": "chase_ur",
        "portal_cpp": 1.25,
        "rewards_by_category": {"dining": 180, "travel": 120, ...},
        "break_even": {"status": "spending_required"}
      },
      ...
    ],
    "spending_source": "user_provided",
    "assumptions": {"redemption_rate": 1.0, "point_value": 0.01}
  },
  "metadata": {...},
  "error": null
}

Recommendations

POST /cards/recommend

Get the best card recommendations for a spending category. From the full market, or from your existing portfolio. Fast deterministic endpoint (<100ms). Use /cards/recommend/verbose for AI-generated narrative (portfolio mode only).

FieldTypeRequiredDescription
categorystringYesSpending category: dining, travel, groceries, gas, etc.
portfolio_card_namesarray[string]NoIf provided, recommend from portfolio instead of market
params.spendingobjectNoMonthly spending by category
params.credit_tierstringNoFilter by credit tier
params.primary_goalstringNoOptimization goal
Request
{
  "category": "dining",
  "params": {
    "spending": {"dining": 600, "groceries": 400},
    "credit_tier": "excellent",
    "primary_goal": "cashback"
  }
}
Response
{
  "success": true,
  "data": {
    "recommendations": [
      {
        "card_name": "American Express Gold Card",
        "issuer": "American Express",
        "annual_fee": 250,
        "net_value": 380,
        "points_program_key": "amex_mr",
        "portal_cpp": 1.1,
        "rewards_structure": "4x dining, 4x groceries..."
      }
    ],
    "category": "dining",
    "spending_source": "user_provided",
    "total_candidates": 8
  },
  "metadata": {...},
  "error": null
}

Renewal Check

POST /card/renewal-check

Check if a card is worth keeping at annual fee renewal time. Returns RENEW, DOWNGRADE, or CANCEL_AND_REPLACE. Fast deterministic endpoint (<100ms).

FieldTypeRequiredDescription
card_namestringYesName of the card to check
params.spendingobjectNoMonthly spending by category
params.primary_goalstringNoOptimization goal
params.credit_tierstringNopoor, fair, good, or excellent
acquired_datestringNoDate card was acquired (YYYY-MM-DD) for anniversary-aware analysis
benefit_selectionsarrayNoBenefit keys the user actually uses (e.g. ["uber", "airline_fee", "dining"]). Selected benefits count at 100%; unselected at 0%.
Request
{
  "card_name": "Chase Sapphire Preferred",
  "acquired_date": "2024-06-15",
  "params": {
    "spending": {
      "dining": 400, "travel": 300, "groceries": 500
    },
    "primary_goal": "travel",
    "credit_tier": "excellent"
  },
  "benefit_selections": ["dining", "travel"]
}
Response
{
  "success": true,
  "data": {
    "verdict": "RENEW",
    "year2_net_value": 120.50,
    "confidence": "high",
    "points_program_key": "chase_ur",
    "portal_cpp": 1.25,
    "spending_source": "user_provided",
    "downgrade_options": [...],
    "replacement_options": [...],
    "thresholds_used": {
      "cancel": -100,
      "keep": 50
    }
  },
  "metadata": {...},
  "error": null
}

POST /card/renewal-check/verbose

Same analysis as the fast endpoint, plus AI-generated retention tips, timing guidance, and a detailed narrative. Response time 3-5s.

Accepts the same parameters as /card/renewal-check. Additional response fields:

Response FieldTypeDescription
detailed_analysisstringAI-generated narrative explaining the verdict
retention_tipsarrayActionable tips for negotiating with the issuer
timing_guidancestringWhen to call and what to say

Card Details

GET /cards/details

Look up comprehensive details for a specific credit card by name. Supports fuzzy matching (e.g. "Sapphire Preferred" matches "Chase Sapphire Preferred Card").

FieldTypeRequiredDescription
card_namestring (query)YesCard name (supports fuzzy matching)
issuerstring (query)NoIssuer name to narrow results (e.g. "Chase")
Request
GET /api/v1/cards/details?card_name=Chase+Sapphire+Preferred
Response
{
  "success": true,
  "data": {
    "card_name": "Chase Sapphire Preferred Card",
    "issuer": "Chase",
    "network": "Visa",
    "card_type": "travel",
    "annual_fee": 95,
    "credit_score_needed": "good",
    "rewards_structure": "3x dining, 2x travel, 1x other",
    "key_benefits": [...],
    "welcome_bonus": "60,000 points",
    "sign_on_bonus": 60000,
    "sign_on_bonus_type": "points",
    "foreign_transaction_fee": "None",
    "apply_url": "https://...",
    "best_for": "Dining and travel rewards",
    "points_program_key": "chase_ur",
    "portal_cpp": 1.25
  },
  "metadata": {...}
}

Card Value

POST /cards/value

Calculate the financial value and break-even point of a credit card based on your spending. Returns first-year value (with sign-on bonus), ongoing annual value, and a WORTH_IT / NOT_WORTH_IT verdict.

FieldTypeRequiredDescription
card_namestringNoCard name for DB lookup (uses actual rewards/benefits if found)
annual_feenumberNoAnnual fee ($). If card_name is provided, pulled from DB.
spendingobjectNoMonthly spending by category, e.g. {"dining": 500, "travel": 300}
benefit_selectionsarrayNoBenefit keys the user uses (100%/0% model)
rewards_structureobjectNoCustom rewards structure (overrides DB if provided)
Request
{
  "card_name": "Chase Sapphire Preferred",
  "spending": {
    "dining": 500, "travel": 300,
    "groceries": 400
  },
  "benefit_selections": ["dining", "travel"]
}
Response
{
  "success": true,
  "data": {
    "first_year": {
      "total_value": 1250,
      "net_value": 1155,
      "sign_on_bonus_value": 750,
      "benefits_utilized": 0,
      "total_rewards": 500
    },
    "ongoing_annual": {
      "total_value": 500,
      "net_value": 405
    },
    "break_even": {
      "monthly_spend_needed": 350
    },
    "rewards_by_category": {
      "dining": 180, "travel": 72, "groceries": 48
    },
    "verdict": "WORTH_IT",
    "spending_source": "user_provided",
    "points_program_key": "chase_ur",
    "portal_cpp": 1.25,
    "assumptions": {...}
  },
  "metadata": {...}
}

Merchant Intelligence

Merchant-level endpoints resolve a merchant name to a spending category, match card credits, and rank your portfolio by reward value. Deterministic for 350+ known merchants; uses Gemini AI fallback for unknown merchants.

POST /which-card-at-merchant

Find the best card from your portfolio for a purchase at a specific merchant. Auto-detects the spending category (e.g. Starbucks → dining) and ranks your cards by reward value.

FieldTypeRequiredDescription
merchantstringYesMerchant name (e.g. "Starbucks", "Saks Fifth Avenue", "Delta Air Lines")
amountnumberNoPurchase amount in dollars (default 100)
portfolioarray[string]YesCard names in your portfolio
Request
{
  "merchant": "Starbucks",
  "amount": 35,
  "portfolio": [
    "Chase Sapphire Reserve",
    "Amex Gold",
    "Citi Double Cash"
  ]
}
Response
{
  "success": true,
  "data": {
    "recommended_card": "American Express Gold Card",
    "category_detected": "dining",
    "category_method": "exact",
    "reason": "Starbucks codes as dining — Amex Gold 4x vs CSR 3x vs Citi DC 2%",
    "earnings_comparison": [
      {
        "card": "American Express Gold Card",
        "multiplier": "4x",
        "points_earned": 140,
        "program": "Membership Rewards",
        "estimated_value": "$2.10"
      },
      ...
    ]
  },
  "metadata": {...}
}

POST /merchant-benefits

Check if any cards in your portfolio have credits or benefits at a specific merchant. Also includes an earning recommendation (which card earns the most here).

FieldTypeRequiredDescription
merchantstringYesMerchant name (e.g. "Saks Fifth Avenue", "Uber", "Disney+")
portfolioarray[string]YesCard names in your portfolio
Request
{
  "merchant": "Saks Fifth Avenue",
  "portfolio": [
    "Amex Platinum",
    "Chase Sapphire Reserve"
  ]
}
Response
{
  "success": true,
  "data": {
    "matching_benefits": [
      {
        "card": "The Platinum Card from American Express",
        "benefit_key": "saks",
        "name": "Saks Fifth Avenue Credit",
        "value": 100,
        "frequency": "semi-annual",
        "schedule": "$50 Jan-Jun, $50 Jul-Dec",
        "note": "Your Amex Platinum has a $100 Saks credit."
      }
    ],
    "earning_recommendation": {
      "best_card": "The Platinum Card from American Express",
      "multiplier": "1x",
      "note": "Use Amex Platinum to combine with the credit."
    }
  },
  "metadata": {...}
}

GET /card-benefits

Get all credits, benefits, and rewards multipliers for a specific card. Returns structured data with value, frequency, schedule, and conditions for each credit.

FieldTypeRequiredDescription
cardstring (query param)YesCard name (e.g. "Amex Platinum", "Chase Sapphire Reserve")
Request
GET /api/v1/card-benefits?card=Amex%20Platinum
Response
{
  "success": true,
  "data": {
    "card": "The Platinum Card from American Express",
    "issuer": "American Express",
    "annual_fee": 695,
    "credits": [
      {
        "benefit_key": "uber",
        "name": "Uber Cash",
        "value": 200,
        "frequency": "monthly",
        "schedule": "$15/mo + $20 Dec"
      },
      ...
    ],
    "total_credit_value": 1584,
    "rewards_multipliers": {
      "airlines": 5, "hotels": 5, "base": 1
    },
    "points_program": "amex_mr",
    "portal_cpp": 1.1
  },
  "metadata": {...}
}

GET /benefit-categories

Returns the benefit key registry — all valid keys for benefit_selections, grouped by category. No authentication required. Use this to discover which keys to pass in portfolio and renewal requests.

Response
{
  "categories": [
    {
      "category": "dining_credit",
      "label": "Dining Credits",
      "keys": ["dining", "resy_dining"]
    },
    {
      "category": "lounge_access",
      "label": "Lounge Access",
      "keys": ["admirals_club", "united_club_membership"]
    },
    ...
  ],
  "all_keys": ["admirals_club", "airline_fee", "avis_budget", ...],
  "usage": {
    "benefit_selections": "Pass keys to portfolio/analyze or card/renewal-check...",
    "benefit_categories_used": "Alternative: pass category names instead..."
  }
}

Card Terms & Risk Data

Schumer Box data: APR, penalties, and fee terms extracted from issuer disclosures. Updated monthly. Covers 148 cards.

GET /cards/{card_id}/terms

Get APR, penalty, and fee terms for a credit card by ID.

FieldTypeRequiredDescription
card_idinteger (path)YesCard ID (from portfolio or search results)
Request
GET /api/v1/cards/42/terms
Response
{
  "success": true,
  "data": {
    "card_id": 42,
    "card_name": "Chase Sapphire Preferred",
    "issuer": "Chase",
    "purchase_apr": "21.49%-28.49%",
    "cash_advance_apr": "29.49%",
    "penalty_apr": "29.99%",
    "balance_transfer_apr": "21.49%-28.49%",
    "late_fee": "Up to $40",
    "returned_payment_fee": "Up to $40",
    "cash_advance_fee": "$10 or 5%",
    "promotional_apr": "0%",
    "promo_apr_months": "12",
    "grace_period_days": "21",
    "last_extracted_at": "2026-04-24T...",
    "extraction_source": "gemini_grounding"
  },
  "metadata": {...}
}

GET /cards/terms

Same data as the ID-based endpoint, but resolves the card by name (fuzzy matching).

FieldTypeRequiredDescription
card_namestring (query)YesCard name (supports fuzzy matching)
issuerstring (query)NoIssuer name to narrow results
Request
GET /api/v1/cards/terms?card_name=Chase+Sapphire+Preferred
Response
Same response format as /cards/{card_id}/terms

Data History & Audit

Append-only change log for card data and points program valuations. Automatically populated by batch jobs — track fee increases, benefit changes, and CPP movements over time.

GET /cards/{card_id}/history

Get change history for a specific card by ID. Returns chronological diffs for any tracked field.

FieldTypeRequiredDescription
card_idinteger (path)YesCard ID
fieldstring (query)NoFilter by field name (e.g. annual_fee, purchase_apr)
sincestring (query)NoISO date string (e.g. 2026-01-01)
Request
GET /api/v1/cards/42/history?field=annual_fee&since=2026-01-01
Response
{
  "card_id": 42,
  "count": 1,
  "changes": [
    {
      "table": "popular_cards",
      "field": "annual_fee",
      "old_value": "95",
      "new_value": "150",
      "detected_at": "2026-03-15T...",
      "source": "weekly_batch_job"
    }
  ]
}

GET /cards/history

Same data as the ID-based endpoint, but resolves the card by name (fuzzy matching).

FieldTypeRequiredDescription
card_namestring (query)YesCard name (supports fuzzy matching)
fieldstring (query)NoFilter by field name
sincestring (query)NoISO date string
Request
GET /api/v1/cards/history?card_name=Chase+Sapphire+Preferred&since=2026-01-01
Response
Same response format as /cards/{card_id}/history

GET /cards/changes

Get all card data changes across all cards since a given date. Useful for monitoring the card landscape for fee increases, benefit removals, or rewards structure changes.

FieldTypeRequiredDescription
sincestring (query)YesISO date string (e.g. 2026-01-01)
fieldsstring (query)NoComma-separated field names to filter (e.g. annual_fee,purchase_apr)
Request
GET /api/v1/cards/changes?since=2026-04-01&fields=annual_fee,penalty_apr
Response
{
  "since": "2026-04-01",
  "count": 3,
  "changes": [
    {
      "card_id": 42,
      "table": "popular_cards",
      "field": "annual_fee",
      "old_value": "95",
      "new_value": "150",
      "detected_at": "2026-04-15T...",
      "source": "weekly_batch_job"
    },
    ...
  ]
}

GET /programs/{program_key}/history

Get CPP and transfer partner ratio change history for a points program. Track valuation trends over time.

FieldTypeRequiredDescription
program_keystring (path)YesProgram key (e.g. chase_ur, amex_mr)
sincestring (query)NoISO date string
Request
GET /api/v1/programs/chase_ur/history?since=2026-01-01
Response
{
  "program_key": "chase_ur",
  "count": 2,
  "changes": [
    {
      "field": "portal_cpp",
      "old_value": "1.25",
      "new_value": "1.50",
      "detected_at": "2026-02-01T...",
      "source": "transfer_partner_refresh"
    },
    ...
  ]
}

Points & Redemption

Points program reference data and redemption strategy generation. Look up transfer partners, check program details, and generate AI-powered redemption playbooks.

GET /points/programs

List all verified, active points programs with portal CPP, transfer partners, and currency names.

Request
GET /api/v1/points/programs
Response
{
  "success": true,
  "data": {
    "count": 11,
    "programs": [
      {
        "program_key": "chase_ur",
        "program_name": "Chase Ultimate Rewards",
        "currency_name": "Ultimate Rewards points",
        "portal_cpp": 1.25,
        "points_expire": false,
        "transfer_partners": [...]
      },
      ...
    ]
  }
}

GET /points/programs/{program_key}

Get a single program's details including transfer partners, portal CPP, and currency info.

FieldTypeRequiredDescription
program_keystring (path)YesProgram key (e.g. chase_ur, amex_mr, cap1_miles)
Request
GET /api/v1/points/programs/amex_mr
Response
{
  "success": true,
  "data": {
    "program_key": "amex_mr",
    "program_name": "Amex Membership Rewards",
    "currency_name": "Membership Rewards points",
    "portal_cpp": 1.1,
    "points_expire": false,
    "transfer_partners": {
      "airlines": ["Delta", "ANA", "Singapore Airlines", ...],
      "hotels": ["Hilton", "Marriott", ...]
    }
  }
}

POST /portfolio/points-playbook

Generate a points redemption playbook for your cards and balances. Returns cashback earning estimates, points-at-risk warnings, and AI-generated per-program redemption strategies with transfer partner suggestions.

FieldTypeRequiredDescription
cardsarray[string]Yes1-10 card names to analyze
point_balancesarrayNoPoint/miles balances: [{"program_key": "chase_ur", "balance": 70000}]
spendingobjectNoMonthly spending by category for cashback calculation
Request
{
  "cards": [
    "Chase Sapphire Reserve",
    "American Express Gold Card"
  ],
  "point_balances": [
    {"program_key": "chase_ur", "balance": 70000},
    {"program_key": "amex_mr", "balance": 50000}
  ],
  "spending": {
    "dining": 500, "travel": 300,
    "groceries": 400
  }
}
Response
{
  "success": true,
  "data": {
    "cashback_earning": {
      "total_annual_cashback": 156.00,
      "cards": ["Citi Double Cash"],
      "summary": "You earn ~$156/year in cashback"
    },
    "points_at_risk": [
      {
        "program": "chase_ur",
        "warning": "Cancel CSR and you lose 70K points"
      }
    ],
    "points_playbook": [
      {
        "program": "Chase Ultimate Rewards",
        "balance": 70000,
        "strategy": "Transfer to Hyatt for 2 nights...",
        "best_transfer": "World of Hyatt (1:1)"
      }
    ]
  },
  "metadata": {...}
}

System

GET /usage

Get your current API usage for the billing period. Returns per-endpoint breakdown, by-channel split (REST vs MCP), and rate limit info.

Request
GET /api/v1/usage
Response
{
  "success": true,
  "data": {
    "period": "2026-05",
    "tier": "free",
    "calls_used": 127,
    "calls_limit": 2000,
    "calls_remaining": 1873,
    "by_endpoint": {
      "/api/v1/portfolio/analyze": 45,
      "/api/v1/cards/compare": 32,
      ...
    },
    "by_channel": {
      "rest": 95,
      "mcp": 32
    },
    "rate_limit": {
      "requests_per_minute": 60,
      "monthly_limit": 2000
    }
  }
}
Try all endpoints interactively in Swagger UI →