/session gates the terminal unlocking, and satoshis_amount_as_fiat() on a
cold cache queries external exchanges (~1 s measured on l484). Read the
LNbits btc-price cache directly instead: warm → fiat, miss → null and
the terminal prices the sats itself. No rate lookup ever blocks a tap.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GET /api/v1/session/{external_id}?p=&c= for bitSpire tap-to-enter. A tap
yields a single-use SUN, so a terminal that verified it at entry could not
reuse the p/c to move sats later. This verifies once (advancing the
counter like /scan), records one hit, and returns what the rest of the
visit needs: the card wallet's balance + fiat equivalent (wallet currency,
then the instance default; display only), the LUD-03 withdraw step
(callback, k1 = hit) and the LUD-06 top-up step (callback), both keyed by
the hit — the same single-use bearer /scan and /pay already hand out.
Withdraw is withheld with a reason once the daily limit is spent, as
/scan would refuse; top-up stays available.
Tests drive the real decrypt/CMAC path with a SUN encrypted under the
card's keys, and pin /verify + /pay behaviour across the helper refactor.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>