bank tranfer fix
All checks were successful
Deploy / build-deploy (push) Successful in 3m11s

This commit is contained in:
Jorijn van der Graaf 2026-08-20 23:33:50 +02:00
commit aaa7a8ce99
10 changed files with 543 additions and 8 deletions

View file

@ -351,6 +351,38 @@ BUNQ_API_KEY=… TRANSFER_IBAN=NL.. \
# -> pulled 2 new credit(s) into /var/lib/catcrafts/orders.jsonl.transfer-credits.jsonl
```
**The key is IP-restricted, and that decides the shape.** Verified the hard way
on 2026-08-20: the bunq API key permits one address (the owner's home
connection), and **bunq enforces that on every request, not only at device
registration**. Registering the server's address in the device's
`permitted_ips` does not help — the device registered fine from home with both
addresses listed, and every read from the server still came back
`"Incorrect API key or IP address"`. So `BUNQ_API_KEY` on the web host cannot
work unless the key's allowlist is widened in the bunq app.
That constraint happens to enforce the right design, so it is now the supported
one: **`tools/pull-and-ship-credits.sh`**, run by a systemd USER timer on the
machine bunq permits (`deploy/catcrafts-credits.{service,timer}`, install
instructions in the service file). It pulls, keeps an accumulating local copy,
and ships **incoming credits only** to the file the rail reads. Outgoing lines
are supplier payments and card spending: the matcher ignores negative amounts,
so shipping them would put the business's outgoing payment history on a
public-facing host for no settlement benefit. The script refuses to overwrite
the remote with an empty file, so an upstream parse failure leaves the server
settling from the last good copy rather than from nothing.
Latency, so nobody wonders: five minutes for the timer plus the reconciler's own
60 s cadence, so a fresh order confirms within about six minutes of the money
landing. Orders more than two hours old back off to a ten-minute poll, so an
older one can take that long.
Two operational notes. The timer only runs while that machine is awake, so
`Persistent=true` makes it pull once on waking rather than silently skipping
every window it missed. And if the home address changes, both the key's
allowlist (in the bunq app) and settlement stop working until it is updated —
the failure mode is silent from the shop's side, so the credits file's mtime is
worth glancing at.
**Read this before deciding where to put the key.** A bunq API key can
**initiate payments**, and bunq offers no read-only scope, so there is no such
thing as a key that can only read. That gives two deployment shapes, and they