Catalog
Read this page as MarkdownIn this section: Catalog endpoints
Catalog endpoints
The free, keyless catalog API: credit card, transfer partner, and point valuation data.
GET /health
Confirms the worker can reach its data store. Not under /v1/public — the router only rewrites /v1/public/* paths, so /v1/health 404s; use this exact URL (or /api/health, an alias).
curl "https://api.askmiles.ai/health"Response:
{
"status": "healthy",
"data_available": true,
"environment": "production",
"timestamp": "2026-08-14T20:03:10.814Z"
}GET /public/credit-cards
Every open card, alphabetical by name. Filter with search, issuer, card_type, or network.
curl "https://api.askmiles.ai/v1/public/credit-cards"Response:
[
{
"id": "chase-sapphire-preferred-credit-card",
"card_name": "Chase Sapphire Preferred Credit Card",
"display_name": "Sapphire Preferred",
"issuer": "Chase",
"card_type": "Personal",
"network": "Visa",
"card_network_tier": "Visa Signature",
"annual_fee": 95,
"foreign_transaction_fee": 0,
"rewards_currency": "Chase Ultimate Rewards",
"welcome_offer_available": true,
"has_statement_credits": true,
"credit_types": ["Global Entry / TSA PreCheck / NEXUS Credit", "..."],
"lounge_networks": [],
"protections": ["Purchase Protection", "..."],
"has_elite_status_benefits": false,
"has_free_night_certificate": false,
"family": {
"family_name": "Chase Ultimate Rewards Personal",
"tier_name": "Sapphire Preferred",
"can_upgrade": true,
"can_downgrade": true
}
}
]family is present only on cards that belong to one.
GET /public/credit-cards/{cardId}
The id is the same URL-safe slug the list endpoint returns, not the card's display name.
curl "https://api.askmiles.ai/v1/public/credit-cards/chase-sapphire-preferred-credit-card"Response:
{ "id": "chase-sapphire-preferred-credit-card", "...": "same shape as the list endpoint's rows" }404s as {"error": "Card not found"} for an unknown or closed card — a closed card’s id simply isn’t in this dataset.
POST /public/credit-cards/search
Same card rows as the list endpoint, filtered by a JSON body instead of query params. An empty body {} returns the same set as the list endpoint.
curl -X POST "https://api.askmiles.ai/v1/public/credit-cards/search" \
-H "Content-Type: application/json" \
-d '{"issuer":"Chase","annual_fee_max":100,"no_foreign_fee":true,"limit":25}'Response:
[ { "id": "amazon-prime-visa-card", "...": "same row shape as the list endpoint" } ]POST /public/benefits-search
Free-text match against benefit names — lounge programs, credits, protections. query is required.
curl -X POST "https://api.askmiles.ai/v1/public/benefits-search" \
-H "Content-Type: application/json" \
-d '{"query":"lounge access","limit":10}'Response:
[
{
"id": "the-platinum-card-from-american-express",
"card_name": "The Platinum Card from American Express",
"display_name": "Amex Platinum",
"issuer": "American Express",
"annual_fee": 895,
"matched_benefits": [
"Lounge: American Express Centurion Lounge",
"Lounge: Priority Pass Select",
"..."
]
}
]GET /public/transfer-partners
Every bank-to-loyalty-program transfer route: which ones exist and which are live. Ratios, bonus size and expiry aren't in the free schema. active_only defaults to true.
curl "https://api.askmiles.ai/v1/public/transfer-partners?has_bonus=true"Response:
{
"source_program": "American Express Membership Rewards",
"dest_program": "Aer Lingus AerClub",
"is_active": true,
"has_transfer_bonus": true
}GET /public/transfer-partners/from/{sourceProgram}
Every destination program reachable from one source. URL-encode the program name; 404s if the source program is unrecognized.
curl "https://api.askmiles.ai/v1/public/transfer-partners/from/Chase%20Ultimate%20Rewards"Response:
[ { "source_program": "Chase Ultimate Rewards", "dest_program": "Emirates Skywards", "is_active": false, "deactivated_date": "2025-06-30" } ]GET /public/transfer-partners/to/{destProgram}
Every source program that can transfer into one destination. Same encoding and 404 behavior as the from/ route.
curl "https://api.askmiles.ai/v1/public/transfer-partners/to/United%20MileagePlus"Response:
[ { "source_program": "Bilt Rewards", "dest_program": "United MileagePlus", "is_active": true, "has_transfer_bonus": false } ]GET /public/valuations
Current cents-per-point value for every tracked currency. programs filters to a comma-separated list of program keys or display names.
curl "https://api.askmiles.ai/v1/public/valuations"Response:
{
"version": "1.0",
"unit": "cents_per_point",
"valuations": {
"chase_ultimate_rewards": {
"value": 1.5,
"display_name": "Chase Ultimate Rewards",
"category": "transferable"
}
},
"updated_at": "2026-08-03T20:00:50.826842+00:00",
"rrv_last_sync": "2026-07-11T03:00:20.750622+00:00",
"created_at": "2026-08-03T19:54:21.300771+00:00"
}category is one of transferable, airline, hotel, restricted, or other — restricted marks a cash-like currency with redemption limits (e.g. Bilt Cash); everything else is a regular transferable, airline, or hotel currency, or other for a program that fits none of those.
GET /public/exports/status
Size and last-modified time for each full-dataset export. /public/exports (no /status) returns the identical payload. Not in openapi.yaml.
curl "https://api.askmiles.ai/v1/public/exports/status"Response:
{
"datasets": {
"credit_cards": {
"available": true,
"size_bytes": 180063,
"last_modified": "2026-08-14T20:01:28.333Z",
"download_url": "/api/public/exports/credit_cards"
}
},
"last_sync": "2026-08-14T20:01:28.672Z"
}GET /public/exports/credit_cards
credit_cards, transfer_partners, or valuations. Unlike every other endpoint here, the response is NOT unwrapped — it's the raw R2 file, envelope included. GET only; a HEAD request 404s. Not in openapi.yaml.
curl "https://api.askmiles.ai/v1/public/exports/credit_cards"Response:
{
"version": "2026-08-14T20:01:28.090722+00:00",
"checksum": "9a50ebfb1603e604",
"count": 186,
"data": [ { "id": "aadvantage-business-world-elite-mastercard", "...": "..." } ]
}POST /mcp
The same free-schema catalog, spoken as Model Context Protocol so an agent can call it without a hand-written client. Keyless like the rest of this API, and unrelated to mcp.askmiles.ai, which is account-scoped and requires OAuth. Five read-only tools: search_card_catalog, get_card_facts, compare_card_facts, find_transfer_routes, estimate_point_value. Handshake revisions 2024-11-05 through 2025-11-25 and the modern 2026-07-28 envelope both work; GET and DELETE return 405, and responses are no-store. Not in openapi.yaml.
curl -X POST "https://api.askmiles.ai/mcp" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_card_catalog","arguments":{"issuer":"Chase","no_foreign_transaction_fee":true}}}'Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"content": [
{ "type": "text", "text": "{ \"cards\": [ ... ], \"miles\": { ... } }" },
{ "type": "text", "text": "Not in this answer: how much each card earns per category; ..." }
],
"structuredContent": {
"cards": [ { "id": "chase-sapphire-preferred", "...": "..." } ],
"matched_count": 3,
"miles": { "source": "Miles · askmiles.ai — ...", "full_answer": "https://askmiles.ai/try?prefill=..." }
}
}
}Every successful result carries a miles object naming what the catalog could not answer, and a link to Miles' own chat. Point valuations in these results are Miles' estimates, not market prices.