Repository navigation
Releases: AxelHamburch/zapbox_extension
Release list
v2.6.4 — GPIO pin added to the successAction message
GPIO pin added to the successAction message (v2.6.4)
The LUD-09 successAction message shown after a payment could be ambiguous when
two switches shared the same label, or a label was changed after the fact —
there was no way to tell which switch actually fired from the confirmation text
alone.
The message now also includes the GPIO pin number:
- With a label:
<Label> - GPIO <pin> - x sats sent - Without a label:
GPIO <pin> - x sats sent
Compatibility
| Component | Required version |
|---|---|
| LNbits | ≥ 1.4.0 |
Upgrade notes
No migration needed. Simply uninstall and reinstall the extension in LNbits so
the updated files are loaded.
v2.6.3 — Switch label in LUD-09 success message
What's new since v2.6.2
Switch label in the LUD-09 success message (v2.6.3)
Wallets that support LUD-09 (successAction) previously only showed a generic
"X sats sent" confirmation after paying a ZapBox invoice, with no indication
of which switch/relay was actually paid for. The success message now prepends
the switch's configured Label (set per pin in the switch editor), e.g.
"Door - 21sats sent" instead of just "21sats sent". If no label is set,
the message is unchanged. The existing "wrong password" warning still appends
as before.
Compatibility
| Component | Required version |
|---|---|
| LNbits | ≥ 1.4.0 |
Upgrade notes
No migrations or breaking changes. Existing switches without a label keep
showing the plain "X sats sent" message; set a Label on a switch to see it
included in the payer's wallet confirmation.
v2.6.2 — PIN entry over the device channel
What's new since v2.6.1
pin_submit over the device channel (v2.6.2)
The 4-digit payment PIN was the last payment-critical step still travelling
over a fresh HTTPS connection — on routers that fail new TLS connections in
phases, the PIN submit could fail exactly while the customer waited at the
PIN pad.
- The channel handler accepts
{"event": "pin_submit", "session_id": "...", "pin": "1234"}with the same validation as the HTTPS endpoint and replies
withpin_submit_result(status/detail) on the same socket - The HTTPS endpoint
POST /api/v1/nfc/pin_submitremains as fallback for
older firmware and for when the channel is down - With this, the complete PIN flow rides the persistent channel:
pin_requiredandpin_error(viapush_to_device()since v2.6.1),
now also the PIN entry itself
Compatibility
| Combination | Result |
|---|---|
| PIN-over-channel firmware + extension v2.6.2 | ✅ intended setup |
| PIN-over-channel firmware + extension v2.6.1 | |
| Older firmware + extension v2.6.2 | ✅ PIN arrives via the HTTPS fallback |
| Component | Required version |
|---|---|
| LNbits | ≥ 1.4.0 |
| ZapBox firmware | PIN-over-channel build (fix/network-stability, commit ab9daca or later) for the full flow |
Upgrade notes
No database migration. Uninstall the old extension in LNbits, install v2.6.2,
flash the matching firmware. Expected log line on the device when a PIN is
entered:
[INFO][PIN] PIN sent over device channel – waiting for WS response
v2.6.1 — Single-connection mode: all events over the device channel
What's new since v2.6.0
Single-connection mode (v2.6.1)
v2.6.0 introduced the device WebSocket channel for Bolt Card taps, but ran it
alongside the core WebSocket — two persistent connections to the same
host:443. On NAT-challenged routers those two connections clobber each other's
tracking entries and both flap in a ~60 s cycle. Observed symptoms: QR
payments rejected with "No active ZapBox connections", invoices paid but the
relay trigger lost, Bolt Card replies arriving while the settlement event
vanished into a half-open socket.
v2.6.1 routes every server→device event through the device channel when it
is connected:
- New module
device_channel.py: registry of connected device channels plus
push_to_device()— device channel first, automatic fallback to the core
WebSocket. Either/or per event, so no duplicate relay triggers. - All push sites converted (relay triggers in
tasks.py,pin_required/
pin_error, teach and auth events, manual trigger endpoint). - The device channel's liveness is proven to the server by the firmware's
protocol pings every 20 s — unlike the core WebSocket, it cannot sit
half-open unnoticed. - The "No active ZapBox connections" check accepts the device channel too:
matching firmware deliberately keeps only that one connection open and
releases the core WebSocket.
Compatibility
| Combination | Result |
|---|---|
| Firmware ≥ single-connection build + extension v2.6.1 | ✅ intended setup — one persistent connection |
| Firmware < v2.6.0 (HTTPS taps) + extension v2.6.1 | ✅ works via fallback |
| Firmware v2.6.0 build + extension v2.6.1 | |
| Single-connection firmware + extension v2.6.0 |
Update firmware and extension together. The v2.6.0 firmware/extension pair
is superseded and should not remain installed.
| Component | Required version |
|---|---|
| LNbits | ≥ 1.4.0 |
| ZapBox firmware | single-connection build (fix/network-stability, commit 5f8949d or later) |
Upgrade notes
No database migration. Uninstall the old extension in LNbits, install v2.6.1,
then flash the matching firmware. Expected log lines on the device:
[NFC-WS] Device channel connected – single-connection mode
[NFC-WS] Releasing core WebSocket — device channel carries all events
v2.6.0 — Device WebSocket channel for Bolt Card taps
What's new since v2.5.4
Device WebSocket channel (v2.6.0)
Bolt Card taps previously reached the server via a fresh HTTPS POST per tap.
Some consumer routers fail new TLS connections in phases (any destination)
while established connections keep working in both directions — on such a
router the NFC payment failed exactly when the phase was bad, while QR
payments (which only ride the established core WebSocket) kept working.
New endpoint: /zapbox/api/v1/ws/nfc/{device_id} — a persistent WebSocket the
device sends events over. A tap now rides an established channel that was
opened once at boot and needs no fresh TLS connection.
{"event": "lnurlw", ...}from the device runs the same payment logic as
the HTTP endpoint (extracted into a sharedprocess_nfc_lnurlw())- The reply (
lnurlw_resultwithstatus/detail/request_id) goes back on
the same socket; handling runs in a spawned task so the channel stays
responsive, replies are serialized per connection - The relay trigger on settlement still arrives via the core WebSocket
(/api/v1/ws/{device_id}) exactly as for QR payments — server pings, the
"No active ZapBox connections" check, and the PIN flow (pin_requiredvia
core WS,pin_submitvia HTTPS) are all unchanged - The HTTP endpoint
POST /zapbox/api/v1/nfc/{device_id}remains as fallback
for older firmware and for when the channel is down — compatible in both
directions
Compatibility
| Component | Required version |
|---|---|
| LNbits | ≥ 1.4.0 |
| ZapBox firmware | any — older firmware keeps using the HTTP endpoint; the channel needs a firmware with serviceNfcWebSocket() (branch fix/network-stability or later) |
| Reverse proxy | must pass WebSocket upgrades on /zapbox/... (usually already configured host-wide for /api/v1/ws/...) |
Upgrade notes
No database migration. Uninstall the old extension in LNbits and install
v2.6.0 so the new module is loaded. Devices reconnect automatically; firmware
with channel support logs Device channel connected – taps use the persistent channel once the new endpoint is live.
v2.5.4 — Fixed: Settled payments
Bug fixes
- Payments settled but the device was never triggered (v2.5.4): the invoice
listener sent the relay trigger viawebsocket_manager.send(...), which no
longer reaches the device's WebSocket on current LNbits versions. The call also
raised, which killed the listener task — so after the first settled payment
no further payment (single, multi-channel, Bolt Card or Mini-PoS) was
reported to the device, even though the invoice was paid. Switchedtasks.py
back to the publicwebsocket_updater(...)helper — the same call every other
trigger in the extension already uses (Identity-Login, NFC-Tag, PIN prompt). - Listener hardening (v2.5.4): a failure while handling one paid invoice can
no longer stop the listener; the error is logged and the next payment is still
processed.
Upgrade notes
Reinstall the extension (uninstall → reinstall).
v2.5.3 — Decoupling GPIO Relays
Relay GPIO is now supplied by the device (v2.5.3)
The extension no longer hard-codes any hardware GPIO. Previously the Mini-PoS
relay pin — and the Identity-Login / NFC-Tag fallback pin — were fixed to a
specific GPIO number in the extension code. When the ZapBox Touch 3.5 channel
layout was re-mapped (the primary channel CH01 moved to GPIO 14), Mini-PoS
stopped switching: the server kept sending the old, now-wrong pin.
The device is the only component that knows its own GPIO layout, so it now tells
the server which relay pin to fire:
- Mini-PoS: the device sends its primary-channel pin in the
POST /zapbox/api/v1/pos/invoicebody ("pin": <gpio>). It is stored with the
invoice and echoed back over WebSocket on settlement. - Identity-Login / NFC-Tag: the
pin/auth_pinquery parameters are now
required (the device already sent them) instead of falling back to a hard-coded
default.
A future re-map of the channel layout needs no server-side change — the
extension holds no GPIO knowledge at all.
v2.5.2 — IdentityLogin: LNURL-auth & NFC tap
What's new since v2.3.0
This release bundles all changes from v2.4.0 through v2.5.2.
LNURL-auth — Identity Login via Lightning Wallet (v2.4.0)
ZapBox can now recognise a known Lightning wallet and trigger a relay — without any payment. The wallet signs a one-time challenge (LNURL-auth / LUD-04); the server verifies the signature and fires the relay.
- New teach mode: 6-tap gesture on the device opens a PIN-gated enrolment screen; the wallet scans a QR code to register its public key
- Up to 3 failed teach-PIN attempts lock the teach access (unlockable in LNbits)
- Teach session auto-expires after 5 minutes
- Each k1 challenge is single-use and valid for ~120 seconds
NFC Identity Login — NTAG 424 DNA / Bolt Ring (v2.5.0)
In addition to wallet login, ZapBox now supports NFC card authentication (Bolt Card, Bolt Ring, or any NTAG 424 DNA card):
- New
/api/v1/nfc/auth/endpoint: verifies tap via tagid_extension, triggers relay WebSocket on a known card - New
/api/v1/nfc/teach/endpoint: enrols a card during teach mode - Management API for enrolled NFC identities (
GET/PUT/DELETE /api/v1/nfc/identities/…) - UI: TagID base URL + invoice key fields and enrolled-cards list in the instance editor
Both methods run in parallel — the LNURL-auth QR is always visible while the NFC reader listens simultaneously.
Instance editor UI redesign (v2.5.0 → v2.5.2)
The Identity Login section was fully restructured for clarity:
- Section is collapsed by default; a single toggle expands all sub-content
- Teach mode toggle and Teach-PIN (6 digits) shown side by side
- LNURL-auth Identities and NFC Identities are clearly separated into named sub-sections
- Section now appears correctly when creating a new ZapBox instance (was hidden during creation)
- Label updated from "NTAG424" to "NFC Tag"
Bug fixes
- bech32 LNURL-auth fix (v2.4.3): wallets received the raw URL instead of the bech32
lnurl1…string — auth flow was not recognised. Fixed:.bech32property is now used correctly. - Migration fix (v2.4.1):
CREATE UNIQUE INDEX zapbox.auth_keyfailed on SQLite (schema-qualified syntax not supported). Replaced with inlineUNIQUEconstraint inCREATE TABLE.
Compatibility
| Component | Required version |
|---|---|
| tagid_extension | v2.1.0+ (for NFC Identity Login) |
Upgrade notes
Migrations run automatically on install. If upgrading from a version before v2.4.1 that left a partial auth_key table, the migration drops and recreates it cleanly.
v2.3.0 - Mini-PoS Support
Server-side support for the new ZapBox Touch 3.5" Mini-PoS mode (firmware v953139t): the device requests a Lightning invoice for a freely entered amount, the extension pushes the settlement back over the existing WebSocket.
Tag: v2.3.0 (db1d610) · Requires: LNbits ≥ 1.4.0 · Firmware: ZapBox Touch 3.5" v953139t for Mini-PoS (older firmware keeps working — fully backwards compatible)
✨ Features
Mini-PoS invoice endpoints
POST /zapbox/api/v1/pos/invoice(X-Api-Key = wallet invoice key): converts amount + currency to sats (fiat viafiat_amount_as_satoshis,sat/satspassthrough), creates the BOLT11 invoice and stores it in the newzapbox.minipos_paymenttableGET /zapbox/api/v1/pos/invoice/last?device_id=...: amount/currency of the last settled Mini-PoS payment — used by the LAST PAY button on the device
Settlement push
- Mini-PoS-tagged settlements mark the payment as paid and push the relay trigger
5-{duration}over the WebSocket — duration taken from the pin 5 switch config (fallback 3000 ms)
Bolt Card pays the pending invoice
/zapbox/api/v1/nfc/{device_id}accepts an optionalminipos_hash: a Bolt Card tap then pays the pending Mini-PoS invoice (stored bolt11) instead of creating a new withdraw — the PIN-limit flow is unchanged
🐛 Fixes
pin_errorWebSocket events carry asession_id, preventing stale events from interfering with a new PIN session- Device is forced into blocked state when the server reports the card as blocked
- Import of
get_minipos_paymentinviews_api.py— Bolt Card Mini-PoS payment threw aNameError(HTTP 500)
🗄️ Database
- New migration m005: table
zapbox.minipos_payment(runs automatically on first start after the update)
📜 Commits since v2.2.0
- db1d610 fix: import get_minipos_payment in views_api - Bolt Card minipos payment threw NameError (HTTP 500)
- c6f17ec feat: release v2.3.0 - Mini-PoS invoice endpoints and settlement push
- f037ee7 feat(minipos): Mini-PoS invoice endpoints and settlement push
- 15648b9 fix: add session_id to pin_error events to prevent stale event interference
- 2b022a6 fix: force blocked state on device when server reports card blocked
- f6f206f fix: update extensions.json hash for v2.2.0 (timeout WS event fix)
📦 Install / Update
Archive: https://github.com/AxelHamburch/zapbox_extension/archive/refs/tags/v2.3.0.zip
SHA256: 630759eb904e9c63b71a92c01ddda579e6ab026e7ae47634f68c00013f34b830 (verified against the tag archive, matches extensions.json on main)
v2.2.0 – Bolt Card PIN Limit Support
What's new
Bolt Card PIN Limit (pinLimit)
ZapBox now supports the pinLimit field from the LUD-XX proposal.
When a Bolt Card has a PIN configured and the payment amount reaches the limit, the ZapBox device shows a PIN entry screen. The user enters 4 digits directly on the touch display — no app or phone required.
Flow:
- Bolt Card tapped → server detects
pinLimitin the LNURLW response - ZapBox shows PIN pad (amount + 4-dot indicator + numpad)
- User enters PIN → sent to server → forwarded to Bolt Card server
- Wrong PIN: error shown for 5 seconds, up to 3 attempts
- Card blocked after 3 failures: 10-second message, then back to normal screen
Changes
views_api.py: PIN session handling withasyncio.Event, newPOST /nfc/pin_submitendpoint, retry loop with WS eventspin_required/pin_error
Requirements
- ZapBox firmware ≥
feature/pin-pad-screen(JC3248W535C with touch display) - boltcards extension on
pin-limitbranch