Compare the total cost of a trip using cash vs points. Factors in transfer ratios, taxes, fees, point valuations, and opportunity cost to recommend the best redemption strategy.
"Should I pay cash or use points?" answered with math.
Compares the true cost of booking with cash versus each available points currency, accounting for transfer ratios, taxes/fees, and the opportunity cost of burning your points.
No API key needed. Uses local JSON data files plus flight/hotel search results.
| File | Purpose |
|---|---|
data/points-valuations.json | CPP valuations per program (floor/ceiling) |
data/transfer-partners.json | Credit card → loyalty program transfer ratios |
The value you're getting per point when redeeming:
cpp = (cash_price - taxes_on_award) / points_needed × 100
A CPP above the floor valuation from points-valuations.json means you're getting above-average value. Below floor = poor redemption.
Points have value even when unspent. Burning 100K Chase UR at 1.7 cpp (floor) means you're "spending" $1,700 in future travel flexibility:
opportunity_cost = points_needed × floor_cpp / 100
If the cash price is lower than the opportunity cost, pay cash. If higher, use points.
IF cash_price < opportunity_cost → PAY CASH (points are worth more saved)
IF cash_price > opportunity_cost → USE POINTS (good redemption)
IF cash_price ≈ opportunity_cost → PAY CASH (preserve flexibility)
The tie goes to cash because points maintain optionality.
Cash prices (use one or more sources):
Duffel API → exact bookable fares
Ignav API → fast comparison prices
Google Flights → browser-based, includes Southwest
Award prices (use seats.aero):
Seats.aero API → cached availability across 25+ programs
Seats.aero web → live search (local Patchright only)
For each award option with a corresponding cash price:
cpp = (cash_price_usd - award_taxes_usd) / award_miles × 100
Award taxes come from seats.aero trip details (TotalTaxes field, in cents) or estimate $5.60 per segment for domestic US, $50-$200 for international (varies wildly by carrier and routing).
If using transferable points (Chase UR, Amex MR, etc.), the effective points cost changes:
effective_points = award_miles / transfer_ratio
effective_cpp = (cash_price - award_taxes) / effective_points × 100
Example: Flying Blue award at 50,000 miles via Capital One (1:1):
Same award via Emirates (Capital One 4:3 ratio):
Load valuations from points-valuations.json:
jq -r '.credit_card_points.chase_ultimate_rewards | "Chase UR: floor \(.floor)cpp, ceiling \(.ceiling)cpp"' data/points-valuations.json
| Rating | CPP vs Floor | Meaning |
|---|---|---|
| Excellent | > ceiling | Exceptional redemption. Book it. |
| Good | > floor | Above average. Solid use of points. |
| Fair | 0.8× to 1× floor | Mediocre. Consider cash instead. |
| Poor | < 0.8× floor | Bad deal. Pay cash. |
Always use markdown tables.
| Option | Program | Miles/Points | Taxes | Cash Equiv | CPP | Rating |
|---|---|---|---|---|---|---|
| Cash | — | — | — | $4,200 | — | — |
| United via Chase UR | United | 88,000 UR | $45 | $1,496 | 4.72 | Excellent |
| Aeroplan via Chase UR | Aeroplan | 75,000 UR | $120 | $1,275 | 5.44 | Excellent |
| Alaska via Bilt | Alaska | 55,000 Bilt | $30 | $935 | 7.58 | Excellent |
| Virgin Atlantic → ANA via Chase UR | VA | 52,500 UR | $200 | $893 | 7.62 | Excellent |
Recommendation:
For round trips, calculate each direction separately. Award pricing is usually one-way, cash pricing is often round-trip. Make sure you're comparing apples to apples:
If cash = round-trip $4,200:
Compare against: outbound award + return award
e.g., 75K out + 75K return = 150K total vs $4,200 cash
CPP = ($4,200 - $240 taxes) / 150,000 = 2.64 cpp
jq -r '.credit_card_points.chase_ultimate_rewards.floor' data/points-valuations.json
# 75,000 Chase UR points
POINTS=75000
FLOOR=$(jq -r '.credit_card_points.chase_ultimate_rewards.floor' data/points-valuations.json)
echo "$POINTS points × $FLOOR cpp = \$$(echo "$POINTS * $FLOOR / 100" | bc) opportunity cost"
# Cash: $4200 round trip. Award: 75000 Aeroplan each way, $120 taxes each way.
CASH=4200
MILES_ONEWAY=75000
TAXES_ONEWAY=120
TOTAL_MILES=$((MILES_ONEWAY * 2))
TOTAL_TAXES=$((TAXES_ONEWAY * 2))
echo "Cash: \$$CASH"
echo "Award: $TOTAL_MILES miles + \$$TOTAL_TAXES taxes"
echo "CPP: $(echo "scale=2; ($CASH - $TOTAL_TAXES) / $TOTAL_MILES * 100" | bc)"
# Opportunity cost at floor valuation
FLOOR=$(jq -r '.credit_card_points.chase_ultimate_rewards.floor' data/points-valuations.json)
echo "Opportunity cost: \$$(echo "scale=0; $TOTAL_MILES * $FLOOR / 100" | bc)"
The same framework works for hotels:
hotel_cpp = (cash_rate_per_night × nights) / total_points × 100
Hotel redemptions vary more than flights. Use points-valuations.json hotel section:
For premium hotel programs (FHR, THC, Chase Edit), factor in the additional benefits (breakfast, upgrade, credit, late checkout) when comparing cash vs points. A $500/night FHR rate with $100 breakfast credit and potential suite upgrade might be worth more than the sticker price.
Chase Sapphire Reserve gives 1.5 cpp in the Chase travel portal (pay-with-points). This sets a floor:
If award CPP < 1.5 → book through Chase portal instead (guaranteed 1.5 cpp)
If award CPP > 1.5 → transfer to partner (better value)
Amex has a similar portal option at lower rates (0.7-1.0 cpp depending on card). Capital One portal gives 0.75-1.0 cpp.
points-valuations.json is the most defensible number.