/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>
/pay and /verify each carried a copy of /scan's card lookup + SUN
decrypt/CMAC/replay checks + counter advance. Extract _authenticate_tap()
(same checks, same order, same reasons) and _client_info() so the fork
endpoints can't drift from upstream's acceptance rules. /scan itself is
untouched (upstream code). No behaviour change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GET /api/v1/verify/{external_id}?p=&c= — side-effect-light SUN check for
access control (doors via the aiolabs extension): confirms a genuine,
non-replayed tap and returns the card identity (external_id, card_name),
WITHOUT /scan's spend semantics (no withdrawRequest, no daily-limit, no hit).
It still advances the SUN counter, so a captured p/c can't be replayed.
Named 'verify' because /auth is already the card-programming OTP endpoint.
config.json → 1.1.1-aio.2.
Add a deposit counterpart to /scan so a Bolt Card can be tapped to
RECEIVE sats, not only spend. The card only emits its lnurlw (a spend
voucher), so the tap is used as an authenticated identity: the same SUN
p/c that /scan verifies proves possession, and we return an lnurl-PAY
(LUD-06) response for the card's own wallet.
- GET /api/v1/pay/{external_id}?p=&c= — SUN-verified, returns a
payRequest; the single-use hit is the callback bearer (like k1 for
withdraw). No daily-limit check (that gates spending); per-deposit max
is tx_limit.
- GET /api/v1/pay/cb/{hit_id}?amount= — invoices the card wallet.
- Static pay metadata so the LUD-06 description_hash matches.
- Distinct from the LUD-19 refund lnurlp (keyed by a prior scan's hit);
this is reachable directly by a tap via external_id.
- config.json → 1.1.1-aio.1 (fork of upstream v1.1.1; upstream left its
config.json at 1.1.0, but the released tag is v1.1.1). README documents
the endpoint.
Consumed by aiolabs/bitspire #84 (Bolt Card tap-to-receive on cash-in).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>