earnrate 0.2.13 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/data/CHANGELOG.md +28 -0
- package/data/VERSION +1 -1
- package/data/cards/amex-delta-skymiles-gold.yaml +7 -8
- package/data/cards/amex-delta-skymiles-platinum.yaml +7 -8
- package/data/cards/amex-delta-skymiles-reserve.yaml +9 -9
- package/data/cards/amex-marriott-bonvoy-business.yaml +7 -8
- package/data/cards/chase-ihg-one-rewards-business.yaml +1 -1
- package/data/cards/discover-it-cash-back.yaml +9 -6
- package/data/cards/venmo-credit-card.yaml +1 -1
- package/data/categories.yaml +10 -0
- package/data/merchants/seed.yaml +3 -1
- package/dist/cli/import.js +14 -11
- package/dist/cli/todo.js +3 -2
- package/dist/cli/wallet.js +50 -17
- package/dist/engine/cheat-sheet.js +15 -11
- package/dist/engine/checklist.js +23 -25
- package/dist/engine/credits.js +2 -2
- package/dist/engine/evaluate.js +1 -1
- package/dist/engine/explore.js +4 -4
- package/dist/engine/intro.js +1 -5
- package/dist/engine/memberships.js +2 -6
- package/dist/engine/offers.js +3 -5
- package/dist/engine/periods.js +5 -0
- package/dist/engine/profiles.js +2 -1
- package/dist/engine/recommend.js +46 -33
- package/dist/engine/record.js +2 -1
- package/dist/engine/rotation.js +2 -1
- package/dist/engine/rule-text.js +98 -33
- package/dist/engine/setup.js +7 -3
- package/dist/engine/simulate.js +4 -4
- package/dist/engine/text.js +29 -8
- package/dist/engine/wallet-change.js +5 -5
- package/dist/engine/wallet-summary.js +24 -21
- package/dist/format/card-text.js +2 -3
- package/dist/format/cards.js +7 -3
- package/dist/format/explore.js +2 -2
- package/dist/format/wallet-yaml.js +13 -17
- package/dist/format/wallet.js +14 -10
- package/dist/import/analyze.js +13 -1
- package/dist/mcp/context.js +2 -3
- package/dist/mcp/inputs.js +3 -3
- package/dist/mcp/schemas.js +2 -0
- package/dist/mcp/server.js +0 -2
- package/dist/mcp/tools/account.js +1 -1
- package/dist/mcp/tools/answers.js +10 -5
- package/dist/mcp/tools/wallet.js +10 -6
- package/dist/schema/card.js +6 -10
- package/dist/schema/merchant.js +3 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -58,11 +58,11 @@ Assumes Whole Foods Market codes as supermarkets (MCC 5411).
|
|
|
58
58
|
Values points at: Amex Membership Rewards (MR) at 1¢, SoFi Member Rewards at 1¢, Chase Ultimate Rewards (UR) at 1¢.
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
Options: `--online` or `--in-store`, `--valuation flat|points-heavy`, `--all`, `--json`, `--date`, `--country`. Run `earnrate --help` for details. To keep the wallet somewhere else, set `EARNRATE_WALLET` to its path.
|
|
61
|
+
Options: `--online` or `--in-store`, `--paying card|apple-pay|google-pay|paypal`, `--valuation flat|points-heavy`, `--cards`, `--member`, `--category`, `--all`, `--json`, `--date`, `--country`. Run `earnrate --help` for details. To keep the wallet somewhere else, set `EARNRATE_WALLET` to its path.
|
|
62
62
|
|
|
63
63
|
`earnrate cheatsheet` prints the card to use for each everyday kind of purchase this quarter (groceries, dining, gas, Amazon, Costco, travel, streaming, drugstores, everything else), with your caps, picks and activations as they are now. `--cards` uses cards you name instead, and `--every-card` picks from every card to show what's worth getting. It's also in the My wallet tab on [earnrate.dev](https://earnrate.dev).
|
|
64
64
|
|
|
65
|
-
`earnrate todo` lists what your saved cards need this quarter, soonest first: bonuses to activate (with Chase's deadline), categories to pick, caps running low
|
|
65
|
+
`earnrate todo` lists what your saved cards need this quarter, soonest first: bonuses to activate (with Chase's deadline), categories to pick, caps running low, welcome bonuses to finish, spend bonuses you're close to, statement credits to enroll in or use, and first-year rates ending. `--ics earnrate.ics` also writes the dates as a calendar file with reminders. My wallet on earnrate.dev shows the same list as "To do now", with an "Add the dates to your calendar" button.
|
|
66
66
|
|
|
67
67
|
`earnrate missed` lists the stores earnrate didn't recognize when you asked here, most asked about first. They're kept only on your computer; [open an issue](https://github.com/cwasley/earnrate/issues) to suggest one for the data.
|
|
68
68
|
|
|
@@ -153,9 +153,9 @@ Every purchase on the card counts. Once earnrate knows how much you've spent on
|
|
|
153
153
|
|
|
154
154
|
`earnrate simulate` adds a bonus's points to a card's yearly rewards when the year's spending on it reaches the total.
|
|
155
155
|
|
|
156
|
-
###
|
|
156
|
+
### Statement credits
|
|
157
157
|
|
|
158
|
-
Some cards give dollars back for spending at a named store, up to a limit each period: Amex Platinum's $75 a quarter at lululemon, Amex Gold's $7 a month at Dunkin', Blue Cash Preferred's $10 a month on Disney+, Hulu or ESPN subscriptions. The purchase still earns the card's rate; the credit comes on top. Asking about the store with no cards saved lists the cards with a credit there first, "With a
|
|
158
|
+
Some cards give dollars back for spending at a named store, up to a limit each period: Amex Platinum's $75 a quarter at lululemon, Amex Gold's $7 a month at Dunkin', Blue Cash Preferred's $10 a month on Disney+, Hulu or ESPN subscriptions. The purchase still earns the card's rate; the credit comes on top. Asking about the store with no cards saved lists the cards with a credit there first, "With a statement credit", in dollars ("$75 back each quarter, then 1x Amex Membership Rewards"), then the usual ranking by rate. A search for a kind of purchase ("clothing") doesn't.
|
|
159
159
|
|
|
160
160
|
With a saved wallet, a credit counts only once you mark it enrolled (these all need enrolling with the issuer), and only while some is left this period. Given an amount, its dollars count toward that card's return and can make it the pick; without one, the answer shows what's left. Recording a purchase from an AI assistant uses it up, and `earnrate todo` reminds you to enroll and to use what's left before the period ends:
|
|
161
161
|
|
|
@@ -240,10 +240,10 @@ Use the connector (or plugin) or the local extension, not both: each keeps its o
|
|
|
240
240
|
- `best_card_for_purchase`: which card to use, with reasons
|
|
241
241
|
- `best_cards_for` and `simulate_spending`: compare every card earnrate knows, for one purchase or a year of spending, with no wallet needed
|
|
242
242
|
- `resolve_merchant`: how a merchant was identified
|
|
243
|
-
- `list_wallet`: a to-do list for your cards right now, then your cards, caps left this period, chosen categories,
|
|
243
|
+
- `list_wallet`: a to-do list for your cards right now, then your cards, caps left this period, chosen categories, statement credits left, welcome-bonus and spend-bonus progress and the point values you've set
|
|
244
244
|
- `cheat_sheet`: the card to use for each everyday kind of purchase this quarter
|
|
245
245
|
- `compare_welcome_offers`: the best public sign-up offers on cards you don't have
|
|
246
|
-
- `record_purchase`: books a purchase against its cap, any open welcome bonus, the card's yearly spend bonuses and an enrolled
|
|
246
|
+
- `record_purchase`: books a purchase against its cap, any open welcome bonus, the card's yearly spend bonuses and an enrolled statement credit in your wallet file, keeping your comments
|
|
247
247
|
- `search_cards`, `add_card`, `update_card`, `remove_card`, `set_memberships` and `set_point_values`: set up the wallet in conversation, including what your points are worth (memberships and point values need no cards)
|
|
248
248
|
|
|
249
249
|
Both servers also offer four prompts, ready-made questions you can pick in Claude instead of typing one. None needs your cards:
|
|
@@ -303,19 +303,19 @@ Every rule in `data/cards/` carries a short quote from the issuer's own page. In
|
|
|
303
303
|
- rules whose quote is no longer on the page, which usually means the rule changed
|
|
304
304
|
- earning lines that appeared or disappeared since the last baseline, such as a new perk
|
|
305
305
|
|
|
306
|
-
A GitHub Action runs it every Monday and opens a "Card source changes" issue when something moved. After updating a card file, run `yarn check-sources --update
|
|
306
|
+
A GitHub Action runs it every Monday and opens a "Card source changes" issue when something moved or a page couldn't be read. After updating a card file, run `yarn check-sources --update --cards <ids>` to record the new baseline for those cards' pages. Some issuers block headless browsers on shared servers; those pages are listed as "couldn't check", and running the command locally covers them. The first run needs `yarn playwright install chromium`.
|
|
307
307
|
|
|
308
308
|
Rotating categories (Freedom Flex) are added each quarter once the issuer posts them. Until then, answers say that quarter's categories are missing rather than guessing.
|
|
309
309
|
|
|
310
310
|
## Privacy Policy
|
|
311
311
|
|
|
312
|
-
earnrate needs no account. The local version has no telemetry; the hosted server counts requests and errors by
|
|
312
|
+
earnrate needs no account. The local version has no telemetry; the hosted server counts requests and errors by tool or page, with the kind of app they came from, and how many wallets are started and used each day, never what was asked. The full policy is at [earnrate.dev/privacy](https://earnrate.dev/privacy); in short:
|
|
313
313
|
|
|
314
|
-
- **The Claude connector:** earnrate's server at mcp.earnrate.dev receives each question Claude asks it (a store or kind of purchase, and any amount, country, spending or cards you gave) and answers without keeping it; request logging is off. It counts requests and errors by
|
|
314
|
+
- **The Claude connector:** earnrate's server at mcp.earnrate.dev receives each question Claude asks it (a store or kind of purchase, and any amount, country, spending or cards you gave) and answers without keeping it; request logging is off. It counts requests and errors by tool or page, with the kind of app they came from, and how many wallets are started and used each day. Connecting it starts an anonymous wallet (a recovery code, no email). It holds only what you save: card IDs and the details you gave, memberships and point values, never card numbers, and is encrypted with its own key that only your recovery code or your connected apps can unlock. Delete it any time; it's deleted automatically after 13 months unused, or a week if it's never used.
|
|
315
315
|
- **What it stores locally:** your wallet, a YAML file on your computer (`~/.earnrate/wallet.yaml` unless you set `EARNRATE_WALLET`). It lists cards by product ID, like `amex-gold`, plus your category picks, activations and how much you've spent toward caps. earnrate never asks for or stores card numbers, expiry dates, security codes or bank logins. When you ask about a store earnrate doesn't recognize, its name goes in `~/.earnrate/missed-merchants.json` (`earnrate missed` lists them; `EARNRATE_MISSED_MERCHANTS=off` keeps no list).
|
|
316
316
|
- **What the local version sends:** nothing, by default. The optional merchant lookup (off unless you turn it on with your own Anthropic API key) sends only the name of a store earnrate doesn't recognize to Anthropic's API, and saves the answer in `~/.earnrate/merchant-cache.json`.
|
|
317
317
|
- **AI assistants:** when you use earnrate through Claude or another assistant, that assistant's provider sees the conversation, including earnrate's answers, under its own privacy policy.
|
|
318
|
-
- **earnrate.dev:** everything you enter on the site stays in your browser. The site counts visits with Cloudflare Web Analytics, without cookies.
|
|
318
|
+
- **earnrate.dev:** everything you enter on the site stays in your browser, except when you add the cheat sheet to Apple Wallet: then pass.earnrate.dev receives what the pass needs (card IDs, picks, activations, checkout names, memberships and the date) and keeps none of it. The site counts which of its parts get used, by name only, and counts visits with Cloudflare Web Analytics, without cookies.
|
|
319
319
|
- **Retention:** locally, your data lives only in files you control, for as long as you keep them. Delete the wallet file, or clear the site's data in your browser, to remove it. A saved wallet on mcp.earnrate.dev lasts until you delete it or leave it unused for 13 months (a week, if it's never used); the record that an app is connected goes after 90 days unused.
|
|
320
320
|
- **Terms:** [earnrate.dev/terms](https://earnrate.dev/terms).
|
|
321
321
|
- **Contact:** [hello@earnrate.dev](mailto:hello@earnrate.dev).
|
package/data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
Every change to card rules, merchants, categories or currencies under `data/`. Bump `data/VERSION` (`YYYY.MM.DD`, plus `.N` for a second release on the same day) and add a section here in the same commit. Each row cites the issuer page the new value came from.
|
|
4
4
|
|
|
5
|
+
## 2026.11.06.1
|
|
6
|
+
|
|
7
|
+
Wording only; no rates changed. Ten categories take `preposition: on`, so answers and pages say "on flights" rather than "at flights": `dining.fast_food`, `grocery.online`, `gas.grocery_store`, `gas.superstore`, `transit.rideshare`, `travel.flights`, `travel.car_rental`, `travel.cruise`, `home_improvement` and `other`.
|
|
8
|
+
|
|
9
|
+
## 2026.11.06
|
|
10
|
+
|
|
11
|
+
Wording only; no rates changed. `discover-it-cash-back`'s welcome-offer note says Cashback Match doubles every rate for the first year, instead of naming the data field it's stored in.
|
|
12
|
+
|
|
13
|
+
## 2026.11.05.2
|
|
14
|
+
|
|
15
|
+
Evidence quotes only; no rates changed. `chase-ihg-one-rewards-business`'s Expensify credit quotes the page's "Enjoy up to $100 in statement credits towards Expensify purchases each calendar year." (a link now splits the old sentence), and `venmo-credit-card`'s foreign transaction fee quotes "No foreign transaction fee" on venmo.com (a footnote number now runs into the old one). Sources: [Chase](https://creditcards.chase.com/business-credit-cards/IHG/business), [Venmo](https://venmo.com/about/creditcard/).
|
|
16
|
+
|
|
17
|
+
## 2026.11.05.1
|
|
18
|
+
|
|
19
|
+
Welcome offers replacing the four that ended 2026-11-04, read on Amex's pages 2026-11-05; none has an end date now. Discover it's foreign transaction fee, from a Discover page that states it.
|
|
20
|
+
|
|
21
|
+
| Card | Field | Was | Now | Sources |
|
|
22
|
+
| ----------------------------- | ------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| amex-delta-skymiles-gold | `welcome_offer` | as high as 80,000 miles + $250 credit after $3,000 in 6 months, ending 2026-11-04 | as high as 80,000 miles after $2,000 in 6 months | [1](https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-gold-american-express-card/25330-10-0#offer-terms) · [2](https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-gold-american-express-card/) |
|
|
24
|
+
| amex-delta-skymiles-platinum | `welcome_offer` | as high as 90,000 miles + $300 credit after $4,000 in 6 months, ending 2026-11-04 | as high as 90,000 miles after $3,000 in 6 months | [1](https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-platinum-american-express-card/25330-10-0#offer-terms) · [2](https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-platinum-american-express-card/) |
|
|
25
|
+
| amex-delta-skymiles-reserve | `welcome_offer` | 50,000 miles + 2 Comfort Flight Certificates after $10,000 in 6 months, ending 2026-11-04 | as high as 125,000 miles after $5,000 in 6 months | [1](https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-reserve-american-express-card/25330-10-0#offer-terms) · [2](https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-reserve-american-express-card/) |
|
|
26
|
+
| amex-marriott-bonvoy-business | `welcome_offer` | 100,000 points + Free Night Award after $8,000 in 6 months, ending 2026-11-04 | 75,000 points after $6,000 in 6 months | [1](https://www.americanexpress.com/en-us/credit-cards/apply/terms/business/prospect/marriott-bonvoy-business-american-express-card/45094-9-0#offer-terms) · [2](https://www.americanexpress.com/us/credit-cards/business/business-credit-cards/amex-marriott-bonvoy-business-credit-card/) |
|
|
27
|
+
| discover-it-cash-back | `foreign_transaction_fee` | unknown | 0 ("Discover® has no foreign transaction fee") | [1](https://www.discover.com/credit-cards/card-smarts/best-international-travel-credit-card/) |
|
|
28
|
+
|
|
29
|
+
## 2026.11.05
|
|
30
|
+
|
|
31
|
+
Wording only; no rates changed. `walmart-plus`, `peloton-membership` and `uber-one` take `preposition: on`, so their credits read "on Walmart+ membership" rather than "at".
|
|
32
|
+
|
|
5
33
|
## 2026.11.04.15
|
|
6
34
|
|
|
7
35
|
Merchant statement credits on every card whose issuer publishes them: 73 new credits on 31 cards, each quoted from the issuer's own pages (read 2026-11-04). With the three already entered, 76 credits on 32 cards. Credits a cardholder must pick a merchant for, ones once every several years, benefits that aren't spending, and the kinds `docs/feature-gaps.md` lists under "Merchant credits the schema can't express" aren't entered. No earn rates changed.
|
package/data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2026.11.
|
|
1
|
+
2026.11.06.1
|
|
@@ -5,7 +5,7 @@ color: '#c9a24f'
|
|
|
5
5
|
issuer: amex
|
|
6
6
|
network: amex
|
|
7
7
|
currency: delta-skymiles
|
|
8
|
-
last_verified: 2026-11-
|
|
8
|
+
last_verified: 2026-11-05
|
|
9
9
|
verified_by: claude
|
|
10
10
|
source_urls:
|
|
11
11
|
- https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-gold-american-express-card/
|
|
@@ -17,12 +17,11 @@ first_year_fee: 0
|
|
|
17
17
|
foreign_transaction_fee: 0
|
|
18
18
|
welcome_offer:
|
|
19
19
|
points: 80000
|
|
20
|
-
spend:
|
|
20
|
+
spend: 2000
|
|
21
21
|
months: 6
|
|
22
|
-
valid_to: 2026-11-04
|
|
23
22
|
varies: true
|
|
24
23
|
not_with: [amex-delta-skymiles-platinum, amex-delta-skymiles-reserve]
|
|
25
|
-
note: 'The public offer is "as high as" 80,000 bonus miles
|
|
24
|
+
note: 'The public offer is "as high as" 80,000 bonus miles; Amex shows the exact miles (which may be lower, or no offer) after you apply and before you accept. Amex: "You may not be eligible for a welcome offer if you have or have had this Card or previous versions of this Card, or if you have or have had the Delta SkyMiles® Platinum American Express Card, the Delta SkyMiles® Reserve American Express Card or previous versions of these Cards." Amex may also decline based on your card history.'
|
|
26
25
|
rules:
|
|
27
26
|
- id: restaurants
|
|
28
27
|
match: { categories: [dining] }
|
|
@@ -116,16 +115,16 @@ evidence:
|
|
|
116
115
|
quote: 'will be $0 for the first year of Card Membership'
|
|
117
116
|
- rule: welcome_offer
|
|
118
117
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-gold-american-express-card/25330-10-0#offer-terms
|
|
119
|
-
quote: 'As High As 80,000 Bonus Miles
|
|
118
|
+
quote: 'As High As 80,000 Bonus Miles'
|
|
120
119
|
- rule: welcome_offer
|
|
121
120
|
url: https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-gold-american-express-card/
|
|
122
|
-
quote: 'after you spend $
|
|
121
|
+
quote: 'after you spend $2,000 in purchases on your new Card within the first 6 months'
|
|
123
122
|
- rule: welcome_offer
|
|
124
123
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-gold-american-express-card/25330-10-0#offer-terms
|
|
125
|
-
quote: '
|
|
124
|
+
quote: 'You can earn these bonus miles after you make $2,000 or more'
|
|
126
125
|
- rule: not_with
|
|
127
126
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-gold-american-express-card/25330-10-0#offer-terms
|
|
128
|
-
quote: 'if you have or have had
|
|
127
|
+
quote: 'if you have or have had the Delta SkyMiles® Platinum American Express Card, the Delta SkyMiles® Reserve American Express Card'
|
|
129
128
|
- rule: foreign_transaction_fee
|
|
130
129
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-gold-american-express-card/25330-10-0#offer-terms
|
|
131
130
|
quote: 'Foreign Transaction None Penalty Fees'
|
|
@@ -5,7 +5,7 @@ color: '#a9abae'
|
|
|
5
5
|
issuer: amex
|
|
6
6
|
network: amex
|
|
7
7
|
currency: delta-skymiles
|
|
8
|
-
last_verified: 2026-11-
|
|
8
|
+
last_verified: 2026-11-05
|
|
9
9
|
verified_by: claude
|
|
10
10
|
source_urls:
|
|
11
11
|
- https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-platinum-american-express-card/
|
|
@@ -16,12 +16,11 @@ annual_fee: 350
|
|
|
16
16
|
foreign_transaction_fee: 0
|
|
17
17
|
welcome_offer:
|
|
18
18
|
points: 90000
|
|
19
|
-
spend:
|
|
19
|
+
spend: 3000
|
|
20
20
|
months: 6
|
|
21
|
-
valid_to: 2026-11-04
|
|
22
21
|
varies: true
|
|
23
22
|
not_with: [amex-delta-skymiles-reserve]
|
|
24
|
-
note: 'The public offer is "as high as" 90,000 bonus miles
|
|
23
|
+
note: 'The public offer is "as high as" 90,000 bonus miles; Amex shows the exact miles (which may be lower, or no offer) after you apply and before you accept. Amex: "You may not be eligible for a welcome offer if you have or have had this Card or previous versions of this Card or if you have or have had the Delta SkyMiles® Reserve American Express Card or previous versions of these Cards." Amex may also decline based on your card history.'
|
|
25
24
|
rules:
|
|
26
25
|
- id: delta
|
|
27
26
|
match: { merchants: [delta, delta-vacations, delta-stays] }
|
|
@@ -118,16 +117,16 @@ evidence:
|
|
|
118
117
|
quote: 'Annual Fee $350 Transaction Fees'
|
|
119
118
|
- rule: welcome_offer
|
|
120
119
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-platinum-american-express-card/25330-10-0#offer-terms
|
|
121
|
-
quote: 'As High As 90,000 Bonus Miles
|
|
120
|
+
quote: 'As High As 90,000 Bonus Miles'
|
|
122
121
|
- rule: welcome_offer
|
|
123
122
|
url: https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-platinum-american-express-card/
|
|
124
|
-
quote: 'after you spend $
|
|
123
|
+
quote: 'after you spend $3,000 in purchases on your new Card within the first 6 months'
|
|
125
124
|
- rule: welcome_offer
|
|
126
125
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-platinum-american-express-card/25330-10-0#offer-terms
|
|
127
|
-
quote: '
|
|
126
|
+
quote: 'You can earn these bonus miles after you make $3,000 or more'
|
|
128
127
|
- rule: not_with
|
|
129
128
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-platinum-american-express-card/25330-10-0#offer-terms
|
|
130
|
-
quote: 'if you have or have had
|
|
129
|
+
quote: 'if you have or have had the Delta SkyMiles® Reserve American Express Card or previous versions of these Cards'
|
|
131
130
|
- rule: foreign_transaction_fee
|
|
132
131
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-platinum-american-express-card/25330-10-0#offer-terms
|
|
133
132
|
quote: 'Foreign Transaction None Penalty Fees'
|
|
@@ -5,7 +5,7 @@ color: '#2b2d33'
|
|
|
5
5
|
issuer: amex
|
|
6
6
|
network: amex
|
|
7
7
|
currency: delta-skymiles
|
|
8
|
-
last_verified: 2026-11-
|
|
8
|
+
last_verified: 2026-11-05
|
|
9
9
|
verified_by: claude
|
|
10
10
|
source_urls:
|
|
11
11
|
- https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-reserve-american-express-card/
|
|
@@ -14,11 +14,11 @@ base_rate: 1
|
|
|
14
14
|
annual_fee: 650
|
|
15
15
|
foreign_transaction_fee: 0
|
|
16
16
|
welcome_offer:
|
|
17
|
-
points:
|
|
18
|
-
spend:
|
|
17
|
+
points: 125000
|
|
18
|
+
spend: 5000
|
|
19
19
|
months: 6
|
|
20
|
-
|
|
21
|
-
note: '
|
|
20
|
+
varies: true
|
|
21
|
+
note: 'The public offer is "as high as" 125,000 bonus miles; Amex shows the exact miles (which may be lower, or no offer) after you apply and before you accept. Amex: "You may not be eligible for a welcome offer if you have or have had this Card or previous versions of this Card." Amex may also decline based on your card history.'
|
|
22
22
|
rules:
|
|
23
23
|
- id: delta
|
|
24
24
|
match: { merchants: [delta, delta-vacations, delta-stays] }
|
|
@@ -80,16 +80,16 @@ evidence:
|
|
|
80
80
|
quote: 'The annual fee for the Delta SkyMiles® Reserve American Express Card is $650.'
|
|
81
81
|
- rule: welcome_offer
|
|
82
82
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-reserve-american-express-card/25330-10-0#offer-terms
|
|
83
|
-
quote: '
|
|
83
|
+
quote: 'As High As 125,000 Bonus Miles'
|
|
84
84
|
- rule: welcome_offer
|
|
85
85
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-reserve-american-express-card/25330-10-0#offer-terms
|
|
86
|
-
quote: 'after you make $
|
|
86
|
+
quote: 'You can earn these bonus miles after you make $5,000 or more'
|
|
87
87
|
- rule: welcome_offer
|
|
88
88
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-reserve-american-express-card/25330-10-0#offer-terms
|
|
89
89
|
quote: 'within your first 6 months of Card Membership'
|
|
90
90
|
- rule: welcome_offer
|
|
91
|
-
url: https://www.americanexpress.com/
|
|
92
|
-
quote: '
|
|
91
|
+
url: https://www.americanexpress.com/us/credit-cards/card/delta-skymiles-reserve-american-express-card/
|
|
92
|
+
quote: 'after you spend $5,000 in purchases on your new Card within the first 6 months'
|
|
93
93
|
- rule: foreign_transaction_fee
|
|
94
94
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/personal/delta-skymiles-reserve-american-express-card/25330-10-0#offer-terms
|
|
95
95
|
quote: 'Foreign Transaction None Penalty Fees'
|
|
@@ -6,7 +6,7 @@ issuer: amex
|
|
|
6
6
|
network: amex
|
|
7
7
|
currency: marriott-bonvoy
|
|
8
8
|
business: true
|
|
9
|
-
last_verified: 2026-11-
|
|
9
|
+
last_verified: 2026-11-05
|
|
10
10
|
verified_by: claude
|
|
11
11
|
source_urls:
|
|
12
12
|
- https://www.americanexpress.com/us/credit-cards/business/business-credit-cards/amex-marriott-bonvoy-business-credit-card/
|
|
@@ -15,11 +15,10 @@ base_rate: 2
|
|
|
15
15
|
annual_fee: 125
|
|
16
16
|
foreign_transaction_fee: 0
|
|
17
17
|
welcome_offer:
|
|
18
|
-
points:
|
|
19
|
-
spend:
|
|
18
|
+
points: 75000
|
|
19
|
+
spend: 6000
|
|
20
20
|
months: 6
|
|
21
|
-
|
|
22
|
-
note: 'Plus a Free Night Award (up to 50,000 points), which earnrate does not value. Amex: "You may not be eligible to receive a welcome offer if you have or have had this Card or the Starwood Preferred Guest® Business Credit Card from American Express or previous versions of these Cards," and may also decline based on your card history. Also not available to anyone who had a Marriott business card from Chase in the last 30 days, opened the Marriott Bonvoy Bountiful, Boundless or Bold card from Chase in the last 90 days, or got a new Card Member bonus on one of those Chase cards in the last 24 months.'
|
|
21
|
+
note: 'Amex: "You may not be eligible to receive a welcome offer if you have or have had this Card or the Starwood Preferred Guest® Business Credit Card from American Express or previous versions of these Cards," and may also decline based on your card history. Also not available to anyone who had a Marriott business card from Chase in the last 30 days, opened the Marriott Bonvoy Bountiful, Boundless or Bold card from Chase in the last 90 days, or got a new Card Member bonus on one of those Chase cards in the last 24 months.'
|
|
23
22
|
rules:
|
|
24
23
|
- id: marriott-hotels
|
|
25
24
|
match: { merchants: [marriott] }
|
|
@@ -102,13 +101,13 @@ evidence:
|
|
|
102
101
|
quote: 'Foreign Transaction None Penalty Fees'
|
|
103
102
|
- rule: welcome_offer
|
|
104
103
|
url: https://www.americanexpress.com/us/credit-cards/business/business-credit-cards/amex-marriott-bonvoy-business-credit-card/
|
|
105
|
-
quote: 'Earn
|
|
104
|
+
quote: 'Earn 75,000 Marriott Bonvoy® Bonus Points'
|
|
106
105
|
- rule: welcome_offer
|
|
107
106
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/business/prospect/marriott-bonvoy-business-american-express-card/45094-9-0#offer-terms
|
|
108
|
-
quote: '
|
|
107
|
+
quote: 'You can earn 75,000 Marriott Bonvoy® bonus points after you complete $6,000 or more'
|
|
109
108
|
- rule: welcome_offer
|
|
110
109
|
url: https://www.americanexpress.com/en-us/credit-cards/apply/terms/business/prospect/marriott-bonvoy-business-american-express-card/45094-9-0#offer-terms
|
|
111
|
-
quote: '
|
|
110
|
+
quote: 'within your first 6 months of Card Membership'
|
|
112
111
|
todo:
|
|
113
112
|
- The welcome offer ends 11/04/2026; re-check the card page for the next one.
|
|
114
113
|
- The welcome offer's Free Night Award isn't valued; a welcome offer holds only points.
|
|
@@ -141,7 +141,7 @@ evidence:
|
|
|
141
141
|
quote: 'up to a maximum accumulation of $100 in a calendar year'
|
|
142
142
|
- rule: expensify
|
|
143
143
|
url: https://creditcards.chase.com/business-credit-cards/IHG/business
|
|
144
|
-
quote: '
|
|
144
|
+
quote: 'Enjoy up to $100 in statement credits towards Expensify purchases each calendar year.'
|
|
145
145
|
todo:
|
|
146
146
|
- "Starting January 1, 2027, $50,000 of purchases in a calendar year earns Diamond Elite status. It isn't listed as a milestone yet, because a milestone has no start date."
|
|
147
147
|
- The $100 airline statement credit (after $250 on flights bought directly each calendar year) isn't modeled.
|
|
@@ -6,7 +6,7 @@ color: '#e8751a'
|
|
|
6
6
|
issuer: discover
|
|
7
7
|
network: discover
|
|
8
8
|
currency: cash
|
|
9
|
-
last_verified: 2026-11-
|
|
9
|
+
last_verified: 2026-11-05
|
|
10
10
|
verified_by: claude
|
|
11
11
|
source_urls:
|
|
12
12
|
- https://www.discover.com/credit-cards/cash-back/it-card/
|
|
@@ -18,16 +18,17 @@ source_urls:
|
|
|
18
18
|
- https://www.discover.com/credit-cards/cash-back/cashback-bonus.html
|
|
19
19
|
# The calendar page's "See our FAQs".
|
|
20
20
|
- https://www.discover.com/credit-cards/card-smarts/using-cashback-bonus/
|
|
21
|
+
# Discover's travel-card article: the only Discover page that states the
|
|
22
|
+
# foreign transaction fee (the application terms' fee table has no row).
|
|
23
|
+
- https://www.discover.com/credit-cards/card-smarts/best-international-travel-credit-card/
|
|
21
24
|
base_rate: 1
|
|
22
25
|
annual_fee: 0
|
|
23
|
-
|
|
24
|
-
# transaction fee row, but nothing says "None".
|
|
25
|
-
foreign_transaction_fee: null
|
|
26
|
+
foreign_transaction_fee: 0
|
|
26
27
|
welcome_offer:
|
|
27
28
|
dollars: 200
|
|
28
29
|
spend: 500
|
|
29
30
|
months: 3
|
|
30
|
-
note: One-time $200 statement credit, available by applying through the card page. Existing or previous cardmembers may not be eligible if they received a new cardmember bonus for this product in the past 48 months. New cardmembers also get Cashback Match, which
|
|
31
|
+
note: One-time $200 statement credit, available by applying through the card page. Existing or previous cardmembers may not be eligible if they received a new cardmember bonus for this product in the past 48 months. New cardmembers also get Cashback Match, which doubles every rate for the first year; earnrate ranks it as a first-year rate, not as part of this offer.
|
|
31
32
|
caps:
|
|
32
33
|
# Discover's quarterly maximum on the rotating 5% categories.
|
|
33
34
|
- id: five-percent-quarterly
|
|
@@ -96,7 +97,6 @@ todo:
|
|
|
96
97
|
- 'Discover has published only 2026 on its 5% calendar (Oct-Dec 2026 is the last quarter shown). Add 2027 quarters when Discover posts them.'
|
|
97
98
|
- Discover's 5% activation isn't retroactive (5% applies "from 10/1/26 (or the date on which you activate 5%, whichever is later)"), and you can activate until the quarter's last day. The schema's activate_by can't say that purchases before activation earn 1%; it's set to the quarter's last day and the rule notes say so.
|
|
98
99
|
- The card page's and application terms' Cashback Match terms say "through your first 365 days"; the Cashback Bonus page says "your first 12 consecutive billing periods or 365 days, whichever is longer". Modeled as 365 days, the shorter. Cash back is matched only when processed within the period, so a purchase in its last days may post too late; earnrate goes by the purchase date.
|
|
99
|
-
- Foreign transaction fee isn't stated on any Discover page or in the application terms (their fee table has no foreign transaction row). Left null; confirm with the Cardmember Agreement or Capital One.
|
|
100
100
|
- Discover says 5% purchases "must be made with merchants in the U.S." The application terms put that sentence in the general earning paragraph, so it may also apply to the 1% base and Capital One Travel; only the rotating rules are marked us_only.
|
|
101
101
|
- Amusement parks, tourist attractions, aquariums, zoos, record stores, video rental, pool halls and bowling alleys earn 5% as Q4 2026 entertainment but have no earnrate category. Golf courses, country clubs and collegiate sporting events are excluded but can't be told apart from the entertainment category.
|
|
102
102
|
- Third-party payment accounts and digital wallet transactions may not earn 5% if they don't carry a qualifying MCC. Not modeled.
|
|
@@ -162,6 +162,9 @@ evidence:
|
|
|
162
162
|
- rule: annual_fee
|
|
163
163
|
url: https://disclosures.capitalone.com/disclosure.42300.en-US.html
|
|
164
164
|
quote: 'Annual Fee None.'
|
|
165
|
+
- rule: foreign_transaction_fee
|
|
166
|
+
url: https://www.discover.com/credit-cards/card-smarts/best-international-travel-credit-card/
|
|
167
|
+
quote: 'Discover® has no foreign transaction fee'
|
|
165
168
|
- rule: annual_fee
|
|
166
169
|
url: https://www.discover.com/credit-cards/cash-back/it-card/
|
|
167
170
|
quote: 'No, there is no annual fee for the Discover it Card.'
|
|
@@ -148,4 +148,4 @@ evidence:
|
|
|
148
148
|
quote: 'Foreign Transaction Fee We will not charge you a foreign transaction fee.'
|
|
149
149
|
- rule: foreign_transaction_fee
|
|
150
150
|
url: https://venmo.com/about/creditcard/
|
|
151
|
-
quote: 'No foreign transaction fee
|
|
151
|
+
quote: 'No foreign transaction fee'
|
package/data/categories.yaml
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
mccs: [5812, 5813, 5814]
|
|
22
22
|
- id: dining.fast_food
|
|
23
23
|
name: Fast food
|
|
24
|
+
preposition: on
|
|
24
25
|
aliases:
|
|
25
26
|
[fast food restaurants, coffee shop, coffee shops, coffee, cafe, cafes]
|
|
26
27
|
mccs: [5814]
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
mccs: [5411]
|
|
36
37
|
- id: grocery.online
|
|
37
38
|
name: Online grocery and delivery
|
|
39
|
+
preposition: on
|
|
38
40
|
aliases: [grocery delivery]
|
|
39
41
|
|
|
40
42
|
- id: superstore
|
|
@@ -57,8 +59,10 @@
|
|
|
57
59
|
mccs: [5541, 5542]
|
|
58
60
|
- id: gas.grocery_store
|
|
59
61
|
name: Gas at grocery stores
|
|
62
|
+
preposition: on
|
|
60
63
|
- id: gas.superstore
|
|
61
64
|
name: Gas at superstores and warehouse clubs
|
|
65
|
+
preposition: on
|
|
62
66
|
- id: ev_charging
|
|
63
67
|
preposition: on
|
|
64
68
|
name: EV charging
|
|
@@ -72,6 +76,7 @@
|
|
|
72
76
|
mccs: [4111, 4112, 4131, 4784, 7523]
|
|
73
77
|
- id: transit.rideshare
|
|
74
78
|
name: Rideshare and taxis
|
|
79
|
+
preposition: on
|
|
75
80
|
aliases: [rideshare, taxi, taxis]
|
|
76
81
|
mccs: [4121]
|
|
77
82
|
|
|
@@ -81,6 +86,7 @@
|
|
|
81
86
|
mccs: [4722]
|
|
82
87
|
- id: travel.flights
|
|
83
88
|
name: Flights
|
|
89
|
+
preposition: on
|
|
84
90
|
aliases: [flights, airfare, airlines, flight, plane tickets]
|
|
85
91
|
mccs: [4511]
|
|
86
92
|
- id: travel.hotels
|
|
@@ -89,10 +95,12 @@
|
|
|
89
95
|
mccs: [7011]
|
|
90
96
|
- id: travel.car_rental
|
|
91
97
|
name: Car rental
|
|
98
|
+
preposition: on
|
|
92
99
|
aliases: [car rentals, rental cars]
|
|
93
100
|
mccs: [7512]
|
|
94
101
|
- id: travel.cruise
|
|
95
102
|
name: Cruises
|
|
103
|
+
preposition: on
|
|
96
104
|
aliases: [cruise]
|
|
97
105
|
mccs: [4411]
|
|
98
106
|
|
|
@@ -149,6 +157,7 @@
|
|
|
149
157
|
mccs: [5941]
|
|
150
158
|
- id: home_improvement
|
|
151
159
|
name: Home improvement
|
|
160
|
+
preposition: on
|
|
152
161
|
aliases: [hardware stores, hardware store, home improvement store]
|
|
153
162
|
mccs: [5200, 5211]
|
|
154
163
|
- id: furniture
|
|
@@ -171,4 +180,5 @@
|
|
|
171
180
|
- id: other
|
|
172
181
|
slug: everyday-spending
|
|
173
182
|
name: Everything else
|
|
183
|
+
preposition: on
|
|
174
184
|
aliases: [everything, everything else, other]
|
package/data/merchants/seed.yaml
CHANGED
|
@@ -748,7 +748,7 @@
|
|
|
748
748
|
|
|
749
749
|
# Transit
|
|
750
750
|
- { id: uber, name: Uber, category: transit.rideshare }
|
|
751
|
-
- { id: uber-one, name: Uber One, category: other }
|
|
751
|
+
- { id: uber-one, name: Uber One, category: other, preposition: on }
|
|
752
752
|
- { id: lyft, name: Lyft, category: transit.rideshare }
|
|
753
753
|
- { id: amtrak, name: Amtrak, domains: [amtrak.com], category: transit }
|
|
754
754
|
- {
|
|
@@ -3359,11 +3359,13 @@
|
|
|
3359
3359
|
name: Walmart+ membership
|
|
3360
3360
|
aliases: [walmart+, walmart+ membership fee]
|
|
3361
3361
|
category: other
|
|
3362
|
+
preposition: on
|
|
3362
3363
|
note: The Walmart+ membership fee, not shopping at Walmart.
|
|
3363
3364
|
- id: peloton-membership
|
|
3364
3365
|
name: Peloton membership
|
|
3365
3366
|
aliases: [peloton all-access, peloton app, peloton app one, peloton strength+]
|
|
3366
3367
|
category: other
|
|
3368
|
+
preposition: on
|
|
3367
3369
|
note: A Peloton membership or app subscription, not equipment.
|
|
3368
3370
|
- id: chatgpt
|
|
3369
3371
|
name: ChatGPT
|
package/dist/cli/import.js
CHANGED
|
@@ -13,20 +13,21 @@ import { cardValuation } from "../engine/valuation.js";
|
|
|
13
13
|
import { analyzeStatement, } from "../import/analyze.js";
|
|
14
14
|
import { parseStatement } from "../import/statement.js";
|
|
15
15
|
import { displayPath, readWallet, RUNTIME_ERROR, USAGE_ERROR, } from "./run.js";
|
|
16
|
-
import { currencyName, dollarsAndCents, periodPhrase } from "../engine/text.js";
|
|
16
|
+
import { currencyName, dollarsAndCents, listed, periodPhrase, } from "../engine/text.js";
|
|
17
17
|
const IMPORT_HELP = `Usage: ${CLI_NAME} import <statement.csv> --card <card-id> [--apply]
|
|
18
18
|
${CLI_NAME} import <statement.csv>:<card-id> [<statement.csv>:<card-id> ...]
|
|
19
19
|
|
|
20
20
|
Reads card statements (Amex and Chase activity CSVs) and reports:
|
|
21
21
|
- what the same purchases would have earned on earnrate's picks
|
|
22
22
|
- where the issuer coded a merchant differently than earnrate assumes
|
|
23
|
-
- the cap usage
|
|
23
|
+
- the cap usage, welcome-bonus and spend-bonus spending, and statement
|
|
24
|
+
credits used that it would record for the current period
|
|
24
25
|
|
|
25
26
|
Name several statements, each with its card, to see one report across them.
|
|
26
27
|
|
|
27
28
|
Nothing is written unless you pass --apply, and then only cap totals,
|
|
28
|
-
welcome-bonus
|
|
29
|
-
importing twice never counts twice.
|
|
29
|
+
welcome-bonus and spend-bonus spending, statement credits used and a
|
|
30
|
+
fingerprint of each recorded purchase, so importing twice never counts twice.
|
|
30
31
|
The statements themselves are never stored.
|
|
31
32
|
|
|
32
33
|
Options:
|
|
@@ -66,10 +67,7 @@ function valuationNote(catalog, wallet, cardIds, profile) {
|
|
|
66
67
|
if (values.size === 0)
|
|
67
68
|
return 'Cash back counted as cash.';
|
|
68
69
|
const parts = [...values].map(([id, cents]) => `${String(cents)}¢ for ${currencyName(catalog, id)}`);
|
|
69
|
-
|
|
70
|
-
? `${parts.slice(0, -1).join(', ')} and ${parts.at(-1) ?? ''}`
|
|
71
|
-
: (parts[0] ?? '');
|
|
72
|
-
return `Points valued at ${list}${profile ? ` (the ${profile} profile)` : ', as in your wallet'}.`;
|
|
70
|
+
return `Points valued at ${listed(parts)}${profile ? ` (the ${profile} profile)` : ', as in your wallet'}.`;
|
|
73
71
|
}
|
|
74
72
|
function formatAnalysis(a, labelOf, valuation, categoryName) {
|
|
75
73
|
const several = a.byCard.length > 1;
|
|
@@ -248,21 +246,26 @@ export async function runImport(argv, io) {
|
|
|
248
246
|
...(milestoneEntries.length > 0
|
|
249
247
|
? [`${String(milestoneEntries.length)} toward spend bonuses`]
|
|
250
248
|
: []),
|
|
249
|
+
...(analysis.credits.length > 0
|
|
250
|
+
? [`${String(analysis.credits.length)} against statement credits`]
|
|
251
|
+
: []),
|
|
251
252
|
];
|
|
252
253
|
if (!values.apply || toRecord.length === 0) {
|
|
253
254
|
io.stdout(values.apply || toRecord.length === 0
|
|
254
255
|
? 'Nothing was written.\n'
|
|
255
|
-
: `Nothing was written. Run again with --apply to record ${toRecord
|
|
256
|
+
: `Nothing was written. Run again with --apply to record ${listed(toRecord)}.\n`);
|
|
256
257
|
return 0;
|
|
257
258
|
}
|
|
258
|
-
await writeProgress(walletFile, analysis.bookings.map((e) => e.booking), analysis.bonuses, analysis.milestones);
|
|
259
|
+
await writeProgress(walletFile, analysis.bookings.map((e) => e.booking), analysis.bonuses, analysis.milestones, analysis.credits.map((e) => e.booking));
|
|
259
260
|
for (const entry of analysis.bookings)
|
|
260
261
|
recorded.add(fingerprint(entry));
|
|
262
|
+
for (const entry of analysis.credits)
|
|
263
|
+
recorded.add(fingerprint(entry, 'credit'));
|
|
261
264
|
for (const entry of bonusEntries)
|
|
262
265
|
recorded.add(fingerprint(entry, 'bonus'));
|
|
263
266
|
for (const entry of milestoneEntries)
|
|
264
267
|
recorded.add(fingerprint(entry, 'milestone'));
|
|
265
268
|
await writeFileAtomic(ledgerFile, `${JSON.stringify({ version: 1, recorded: [...recorded] }, null, 2)}\n`);
|
|
266
|
-
io.stdout(`Recorded ${toRecord
|
|
269
|
+
io.stdout(`Recorded ${listed(toRecord)} in ${displayPath(walletFile)}.\n`);
|
|
267
270
|
return 0;
|
|
268
271
|
}
|
package/dist/cli/todo.js
CHANGED
|
@@ -9,8 +9,9 @@ import { displayPath, readWallet, RUNTIME_ERROR, USAGE_ERROR, } from "./run.js";
|
|
|
9
9
|
const TODO_HELP = `Usage: ${CLI_NAME} todo [--ics <file>] [--date <YYYY-MM-DD>]
|
|
10
10
|
|
|
11
11
|
What your saved cards need this period, soonest first: bonuses to activate,
|
|
12
|
-
categories to pick, spending caps running low, welcome bonuses to finish,
|
|
13
|
-
|
|
12
|
+
categories to pick, spending caps running low, welcome bonuses to finish,
|
|
13
|
+
spend bonuses you're close to, statement credits to enroll in or use, first-year
|
|
14
|
+
rates ending, and rotating categories the issuer hasn't posted yet.
|
|
14
15
|
|
|
15
16
|
Options:
|
|
16
17
|
--ics <file> Also write the dated items as a calendar file to import
|