In this section: Changelog

Changelog

Dated changes to the MCP server and the Chat API that a client could notice, newest first.

An entry marked Breaking changes a field, header or result shape a client may already rely on, so that client's code has to change. Stability lists what Miles promises never to change.

Additions that do not change an existing field (a new optional parameter, a new tool) are not listed individually; the tool reference is generated from the live server and is always current.

2026-09-21

  • BreakingMCPChat API#

    get_wallet_card refuses a card_name that matches two holdings one member holds with error: "ambiguous_holding" and a holdings list. That is the code and the key analyze_keep_cancel already answers the same situation with, so one refusal is now handled one way. It used to answer multiple_matches with matches. Both old names ride along until 2026-12-31: matches stays as a copy of holdings, and previous_error carries multiple_matches. A client that branches on error should read ambiguous_holding and take holdings[].wallet_id before then. multiple_matches is unchanged on update_card, remove_card, the gift card tools and the watchlist, where the rows are not holdings and the retry takes a different argument.

  • MCPDocs#

    A coded refusal now carries docs, an absolute link to that code's anchor on the new Error codes reference. On a tool result it sits beside error, message and fix; over MCP it sits inside the error object under structuredContent.result. Nothing was removed or renamed, the advertised output schema is unchanged, and a refusal whose error is a sentence rather than a code carries no docs. The Chat API's OpenAI-shaped envelope is untouched.

2026-09-19

  • MCPChat API#

    set_free_night_status and set_certificate_status take three new optional fields: note (what a certificate is for or where it is booked, up to 500 characters), earned_on and expires_on (the member's own dates, read off the issuer). status is no longer required as long as one of the three is given. A note comes back wrapped as untrusted content on get_free_nights and get_certificates, since the person or an agent may have written it. An expiry_basis of member_supplied marks a date the member entered directly, same as from_earned_on.

2026-09-17

  • BreakingMCPChat API#

    get_eligibility answers the American Express card limit correctly. issuer_status["American Express"].eligible is true only while both caps have room; it used to be true while either one did, so an account six credit cards over its five card limit read as eligible. Read the new credit_card_eligible and charge_card_eligible for the cap a specific card falls under. When a card is named, card_eligibility now returns eligible: false with the cap sentence in reason and a portfolio_blockers list, where it returned "No restrictions found".

2026-09-11

  • MCPChat API#

    Every card's image_url now carries a ?v= query string that changes when the art is redrawn. The path before it is unchanged and still serves the image on its own; a client that trims the query gets the same file with a shorter cache life. Ask Cloudflare for a smaller copy with /cdn-cgi/image/width=W,quality=85,format=auto,onerror=redirect in front of the path, where W is one of 128, 200, 256, 400, 600, 800 or 1200; other option strings are refused.

  • MCPChat API#

    set_credit_usage no longer refuses a free account with supporter_required. For a free account, get_credit_usage, set_credit_usage and clear_credit_usage leave out totals and each row's history; a Member's results are unchanged.

  • MCP#

    An agent's set_credit_usage no longer replaces a credit period the person recorded themselves: that entry comes back skipped with reason: "member_recorded" and the existing answer. Send overwrite: true only when the person asks to replace it.

  • MCPChat API#

    analyze_keep_cancel values a member's credits from the usage they recorded once enough periods are on record, so a verdict can change with no field removed. credit_value_basis says which basis an answer used (recorded, typical or mixed), and basis: "typical" asks for the previous estimate.

  • MCPChat API#

    analyze_keep_cancel refuses a card_name that matches two or more cards in the member's wallet with error: "ambiguous_holding" and a holdings list, where it used to analyze the first match. Call it again with one holdings[].wallet_id as wallet_id; card_name is optional when wallet_id is given.

2026-09-10

  • MCP#

    set_free_night_status declares status as required in its input schema. A call without it was already refused inside the tool; it is now refused by input validation, before the tool runs.

2026-09-09

  • MCPChat API#

    get_eligibility counts American Express credit cards and charge cards against separate caps. issuer_status["American Express"].credit_card_count counts credit cards only (it counted every open Amex card), the new charge_card_count counts charge cards, and notes reports both counts against their own caps.

2026-09-08

  • BreakingChat API#

    The monthly counter became a monthly budget. x-miles-quota-limit-month and x-miles-quota-remaining-month are replaced by x-miles-budget-percent-used and x-miles-budget-reset-date, no alias -- see Stability. A spent budget still refuses as insufficient_quota, with Retry-After now the seconds until the reset date rather than a short window.

  • Chat API#

    The daily spend ceiling is one count per account, shared by web chat and the Chat API; each server process used to keep its own. It resets at midnight Pacific instead of rolling over 24 hours.

2026-09-07

  • Chat API#

    /v1/chat/completions enforces a daily spend ceiling per account. Past it, a turn is refused 429 rate_limit_exceeded with Retry-After: 3600. The per-minute window refuses with the same code, so branch on Retry-After; see Rate limits.

  • Chat API#

    GET /v1/models has its own rate limit and can refuse 429 rate_limit_exceeded with Retry-After.

  • MCP#

    When the connection refuses a batch add_card partway (paused, read-only, or over a daily ceiling), the answer is one isError result carrying the entries that landed, error and stopped_at_index. Every remaining entry used to come back rejected as a malformed result.

  • MCP#

    A card date that is not YYYY-MM-DD is refused with a typed error: "invalid_<field>": date_opened, anniversary_date and signup_bonus_received_on, plus review_by, fee_posts_on and new_anniversary_date on update_card. update_card with product_change: true used to drop a malformed date silently; it is refused now.

  • OAuth#

    A refresh_token grant that sends scope gets a token pair holding only those scopes, and the narrowing is permanent for that grant. scope used to be ignored on refresh.

2026-09-06

  • BreakingMCP#

    The wallet_card that add_card and update_card echo back carries the member's own values as user_sign_up_bonus and user_notes, the spelling get_wallet_cards already used; sign_up_bonus and notes on a card you read are the catalog's. The write parameters keep their names. No alias; Stability records it as an exception to its promise.

  • BreakingMCP#

    A card write with expected_updated_at against a card that has no stored updated_at is refused error: "unguardable_card", where it used to return stale_precondition, which a re-read could never clear. Stability records it as an exception to its promise.

  • MCP#

    get_card_info refuses a wallet_id that is not shaped like one (cc_12) and says to pass card_name instead. It used to fall through to a fuzzy catalog match.

  • MCP#

    update_card is annotated destructiveHint: true, since it can now clear a field. A client that confirms destructive calls with the person will now confirm this one.

  • MCP#

    get_needs_attention items can carry a new kind, status_entitlement: an elite-status entitlement about to expire, with no card attached. It never makes has_items true on its own.

  • OAuthMCP#

    A new scope, miles:write:reconcile, granted by its own consent toggle, covers set_credit_usage, set_free_night_status and set_certificate_status and no other write. miles:write still covers all three. A token's scope can now read miles:read miles:write:reconcile.

2026-09-04

  • Docs#

    This section. Every page has a markdown twin at the same URL with .md, and /docs/mcp/tools.md lists every tool in one file.

  • Chat API#

    /developers.md, a markdown twin of the developers page.

2026-08-27

  • Chat API#

    Every response carries x-ratelimit-limit-requests, x-ratelimit-remaining-requests and x-ratelimit-reset-requests; a metered account also gets x-miles-quota-limit-month and x-miles-quota-remaining-month. Nothing new is enforced.

  • OAuth#

    Access tokens, refresh tokens and authorization codes carry the prefixes miles_at_, miles_rt_ and miles_ac_. Personal keys had miles_sk_ already.

2026-08-26

  • Skills#

    /skills/ask-miles.md published; listed on ClawHub the same day.

2026-08-20

  • BreakingMCP#

    Refusals arrive as isError results with structuredContent.result.error.code, not as ordinary JSON text. Stability records it as an exception to its promise.

2026-08-18

  • MCP#

    Gift-card writes (add_gift_card, update_gift_card, remove_gift_card) exposed; a card number is never echoed back in a result.

2026-08-13

  • MCP#

    Daily ceilings: 50 knowledge_search calls, 500 calls, 100 writes, 1,000 changed rows per user, reset at midnight Pacific.

2026-08-10

  • MCP#

    Server moved to the MCP specification's 2026-07-28 revision. Both protocol eras are served from the one /mcp endpoint.