feat(lnurl): /session — one verified tap for a terminal visit #1

Merged
padreug merged 2 commits from feat/card-session-endpoint into main 2026-09-20 15:16:37 +00:00
Owner

Adds GET /api/v1/session/{external_id}?p=&c= for bitSpire tap-to-enter (aiolabs/bitspire ADR-003).

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. /session verifies once (advancing the counter exactly 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 are 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.

First commit extracts the SUN check /pay and /verify each copied from /scan into one helper so the fork endpoints can't drift from upstream's rules. /scan itself is untouched.

Tests drive the real decrypt/CMAC path with a SUN encrypted under the card's keys and pin /verify + /pay behaviour across the refactor. Consumer: aiolabs/bitspire feat/boltcard-session-balance, which also carries the wire doc (docs/boltcard-session.md).

Adds GET /api/v1/session/{external_id}?p=&c= for bitSpire tap-to-enter (aiolabs/bitspire ADR-003). 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. /session verifies once (advancing the counter exactly 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 are 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. First commit extracts the SUN check /pay and /verify each copied from /scan into one helper so the fork endpoints can't drift from upstream's rules. /scan itself is untouched. Tests drive the real decrypt/CMAC path with a SUN encrypted under the card's keys and pin /verify + /pay behaviour across the refactor. Consumer: aiolabs/bitspire feat/boltcard-session-balance, which also carries the wire doc (docs/boltcard-session.md).
/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>
feat(lnurl): /session — one verified tap for a terminal visit
Some checks failed
lint.yml / feat(lnurl): /session — one verified tap for a terminal visit (pull_request) Failing after 0s
4e9cd78b59
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>
padreug deleted branch feat/card-session-endpoint 2026-09-20 15:16:37 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/boltcards!1
No description provided.