Open API

The Finstracker recommender, over HTTP.

One endpoint. Optional auth. Returns the same ranked card list the Finstracker app uses for "what should I swipe right now?" — so you can drop it into your own checkout, browser extension, or assistant.

GET /api/cards/best

Returns a ranked list of cards from the public catalog (and, when authenticated, from the user's own active merchant offers) for a given context — a merchant, a category, or a full monthly spend mix.

Query parameters

ParamTypeNotes
merchantstringCase-insensitive substring match against the authenticated user's active Offers. Surfaces matching offers at the top of the list with reason: "active merchant offer".
categorystringOne of dining, groceries, travel, gas, streaming, transit, online_retail, drugstores. Used with amountCents for single-purchase shorthand.
amountCentsintegerOptional purchase amount (cents). Drives the expectedPoints / expectedDollarValue math when category is supplied.
spendMixJSONURL-encoded JSON object of {category: monthlyUSD}. Used in place of category+amountCents when you have a full picture of monthly spend.
homeAirportstring (≤4 chars)IATA code. Powers the redemption-fit factor — cards whose transfer partners actually fly from this airport float to the top.
intentearn | travelDefaults to earn. When travel, the redemption-fit factor is applied even if goal isn't set.
goalstringOptional explicit goal: cashback | travel | hotels | sub | credit.
lat, lngnumberReserved for the Tier-6.3 PWA "best card nearby" use case. Accepted and echoed back in inputs; not currently used for scoring.
excludeOwnedbooleanDefaults to true when authenticated. Drops cards already in the user's wallet from the catalog list.
limitinteger1–20. Default 5.

Authentication

Optional. Without a token, the endpoint returns catalog-based recommendations only. With a Authorization: Bearer <jwt> header from POST /api/auth/login, the endpoint additionally factors in:

  • Your owned cards (excluded from recommendations unless excludeOwned=false).
  • Your travelProfile (home airport, hotel chains) merged with query-string overrides.
  • Your active Offers (when merchant is supplied) — surfaced at the top of the list.

Rate limits

Best-effort 60 requests / minute / IP. There is no hard enforcement today; abusive callers will be IP-blocked at the edge. Please cache aggressively — recommendations are stable for a given input within a minute.

Example — anonymous, single-merchant context

curl -s 'https://finstracker.com/api/cards/best?merchant=Whole+Foods&category=groceries&amountCents=5000'
const url = new URL("https://finstracker.com/api/cards/best");
url.search = new URLSearchParams({
    merchant: "Whole Foods",
    category: "groceries",
    amountCents: "5000",
});
const res = await fetch(url);
const { data } = await res.json();
console.log(data.recommendations[0]);

Example — authenticated, travel intent

curl -s 'https://finstracker.com/api/cards/best?intent=travel&homeAirport=SAT&spendMix=%7B%22dining%22%3A300%2C%22travel%22%3A200%7D' \
  -H 'authorization: Bearer YOUR_JWT_HERE'

Response shape

All Finstracker responses use the standard {status, message, data} envelope.

{
  "status": 200,
  "message": "Recommendations computed",
  "data": {
    "recommendations": [
      {
        "cardId": null,
        "cardKey": "chase-sapphire-reserve",
        "displayName": "Sapphire Reserve",
        "issuer": "Chase",
        "pointType": "chase_ur",
        "annualFee": 550,
        "expectedPoints": 7200,
        "expectedDollarValue": 540.00,
        "score": 675.00,
        "redemptionFit": 1.25,
        "reason": "earns CHASE UR → transfers to United, which flies from SAT — 3× travel × $200/mo × 1.5¢ = $108/yr"
      }
    ],
    "inputs": {
      "spendMix": {"travel": 200, "dining": 300},
      "goal": "travel",
      "homeAirport": "SAT",
      "intent": "travel",
      "lat": null,
      "lng": null,
      "excludeOwned": false,
      "authenticated": true,
      "excludedKeys": []
    }
  }
}

Per-recommendation fields: cardId is non-null only for active-offer hits backed by a user's own card; expectedPoints is the gross yearly points / cash-equivalent units; expectedDollarValue is the dollar value after annual-fee deduction; redemptionFit is the 0.5–1.25 factor from redemption-fit scoring.

Build something with it.

The endpoint is free and unauthenticated. The deeper recommendations come once you sign in.

Create a free account