Changelog

API changes, new endpoints, and data additions — most recent first. Atom feed

  • Changed: reward_rates[].category_slug (and category_rate.category_slug on GET /v1/cards/best) is now a clean label built from the rate's categories, merchant, booking_channel and choice_group: <categories>[:<merchant>][@portal|@direct][#choice][~<tag>]. For example "everything" is now "other", "united_flights" is now "airlines:united-airlines", and a rate earned only through the issuer's travel portal ends in "@portal". The same rate has the same label on every card. A ~tag ("~3x") appears only when two rates of one card would otherwise share a label, and it can change when the card's other rates change. Every stored rate is relabelled once when this ships; that one-off relabel bumps each card's updated_at but sends no card.updated webhook, so re-fetch your cards or sync by updated_at. To match rates, use categories, merchant, booking_channel and choice_group, not the label. GET /v1/cards/best?category= also accepts a label that names one category ("dining#choice", "travel@portal")
  • Fixed: card change history (GET /v1/cards/:slug/history) stopped recording in late March because automated updates skipped it -- every published change to a tracked field is recorded again. A reworded welcome offer with the same headline number is not counted as a change
  • Fixed: webhooks now fire for automated updates and staff edits, and only when something changed. card.updated carries the changed fields with their old and new values and names the related tables that changed (changed_relations); card.created fires when a card is published or comes back, and card.deleted when it is discontinued or unpublished (data.reason says which)
  • Fixed: GET /v1/product-changes was always empty because extracted product change options were dropped. Paths are now saved when an issuer's page names the card a product can switch to; coverage is still limited
  • Fixed: image_url could hold an issuer logo, a navigation icon or a tracking pixel instead of card art. Those are no longer stored or served (image_url is null instead)
  • Changed: Enterprise no longer lists affiliate links, which the API never had data for
  • Fixed: card history could list changes that weren't changes, shown as "null -> undefined" (a field the March 2026 scrapes did not return), empty to empty, or the same value spelled differently ("cashback" / "cash_back"). Those entries are left out, and a history entry always has both an old and a new value (either may be null)
  • New: 401, 403 and 429 errors add upgrade_url and docs_url to the error object, and a 429 also says which plan and limit was hit (plan, limit: daily or monthly, limit_value) and what the next plan gives. code and message keep their meaning. Every response to a known key carries an X-CardAPI-Plan header, and https://api.cardapi.dev/ answers a JSON index (docs, sign-up, OpenAPI) instead of a 404
  • Changed: the API's address is https://api.cardapi.dev in the docs, the Postman collection, the OpenAPI spec and both SDKs' defaults. The previous Railway address keeps working
  • New: try GET /v1/cards/:slug without a key on the homepage and /docs. It returns the Free plan's fields, the same as a new free key. The cardapi.dev/compare demo now shows Free-plan fields too, and marks the rows that need Starter
  • New: live card comparison tool at cardapi.dev/compare -- search and compare 2-4 cards side by side, powered by the same public API
  • GET /v1/cards/search now ranks results by relevance (exact name match, then name prefix, then name contains, then issuer match) instead of alphabetically
  • Fixed: GET /v1/cards/search was returning a 500 error on every real query -- now fixed and relevance-ranked
  • Fixed: GET /v1/cards/:slug/transfers always returned an empty array for every card -- now correctly resolves Chase Ultimate Rewards, Amex Membership Rewards, Citi ThankYou, and Capital One transfer partners
  • Fixed: GET /v1/cards can now actually filter out discontinued cards via ?include_discontinued=true (previously had no effect)
  • Fixed: GET /v1/stats issuer-by-country counts were off by one due to an inactive issuer being counted inconsistently
  • Massive data expansion: 30+ new fields per card including balance transfer offers, intro APR, detailed fee schedules, authorized user policies, military/SCRA benefits (each filled in only where the issuer's page states it, so many cards have them empty)
  • New tables: statement_credits (airline credits, Uber cash, streaming), card_perks (hotel status, TSA PreCheck, airline perks), spend_bonuses (spending-based tier unlocks)
  • Point/mile valuations: cents-per-point values for UR, MR, TYP, Capital One, Bilt, and Canadian currencies
  • Card material & design data: metal vs plastic, contactless, card color, vertical orientation
  • Product change paths: which cards can be upgraded/downgraded to which
  • AI-powered card image extraction: hybrid CSS selectors + Claude vision for accurate card art
  • Expanded to 37 issuer configurations (15 new Phase 2 issuers)
  • Added 9 new card fields: referral_bonus_amount, product_family, churning_notes, application_rules, etc.
  • New issuers: Bilt, PenFed, Navy Federal (22 total, up from 20)
  • Removed HSBC Canada (acquired by RBC)
  • Scraper reliability improvements: failure recording, health dashboard
  • Developer portal: Google + GitHub OAuth, interactive API explorer, Google One Tap
  • Python SDK released
  • Card history endpoint: GET /v1/cards/:slug/history
  • Transfer partners endpoint: GET /v1/cards/:slug/transfers
  • Application rules endpoint: GET /v1/application-rules
  • Notable offers endpoint: GET /v1/offers/notable
  • Initial API launch
  • 56 cards across 20 issuers (US + Canada)
  • TypeScript SDK (@cardapi/client)
  • Stripe billing integration (Free / Pro / Enterprise)
  • Webhook support for Enterprise tier

Build on the data: 100 free calls a day, no card needed.

Get a free key