Template updates
Your treasury node runs from a versioned Railway template. New template versions ship bug fixes, security hardening, and new features. This page covers how you're expected to find out about updates and apply them — updates are always merchant-initiated; ZuPayments never pushes code to your infrastructure.
Why updates are never automatic
Self-custody means your Railway project is the root of trust for your node. Nothing about ZuPayments' design lets the platform reach into your infrastructure and change what's running there — not for updates, not for anything. If it could, that would be a hole in the exact guarantee the whole product is built on: that ZuPayments structurally cannot touch your keys or your code. So template updates are something you pull, on your own schedule, never something pushed to you.
How you'll find out about an update
Your node exposes its own template version at a small discovery endpoint
(/.well-known/zupay-node) that reports {node_id, template_version, pubkey_fingerprint}. This part is live and stable (D8.19,
apps/node/src/health/discovery.ts).
What's now built on the platform side (ZUP-45, not yet true when this page was first drafted):
- A
template_versionscatalog table records each released Railway template version — its semver, an optional changelog, a Railway template ref for building a redeploy link, and whether it's flagged security-critical (apps/platform/src/server/releases/catalog.ts). GET /dashboard/template-updatesis a real, mounted, authenticated route (session + onboarded, same gate as the rest of/dashboard/*—apps/platform/src/app.ts). For each node you've registered, it returns whether an update is available and, if so, the target version, changelog, a Railway redeploy deep-link, and aseverityof"routine"or"security". The comparison is pure semver —major.minor.patchonly, hand-rolled rather than pulling in a dependency (apps/platform/src/server/releases/semver.ts) — and a node with no reported version, or one already at or ahead of the latest published version, correctly gets no nudge rather than a false "out of date" claim (notifications.ts, unit-tested independent of Postgres).- Severity is elevated to
"security"whenever any published version strictly newer than your node's current version is flagged security-critical — not only when the very latest release happens to be the security one — so you can't miss an in-between security fix by jumping straight to the newest release. - This surface is read-only and self-custody-safe by construction: it computes a notification and a Railway deep-link; it never calls your node or triggers a redeploy itself (D5.8, golden rule 5).
What's still missing: there is no dashboard UI to display any of this.
The platform (apps/platform) is currently an API-only backend with no
merchant-facing frontend built — GET /dashboard/template-updates works if
you call it directly with a valid session, but there is nowhere in a browser
UI today where you'd see an "update available" badge. Treat this the same
way as before: check the ZuPayments changelog/release notes directly rather
than expecting an in-dashboard prompt, until a dashboard frontend exists to
render this endpoint.
One more accuracy note: your node's recorded template_version is only
refreshed when you (re-)register the node with the platform — the platform
does not poll your node's /.well-known/zupay-node on any schedule
(apps/platform/src/nodes/routes.ts, POST /register is the only write
path to nodes.templateVersion, on both first registration and
re-registration). If you update your node's template without re-registering
it, the platform's record of your version can lag behind what's actually
deployed until you next register.
Applying an update
Until a guided in-dashboard flow ships, updating means redeploying your node
service from the newer template version through Railway directly — the same
mechanism as the initial deploy in deploy.md, just targeting
a newer template version instead of a fresh project. Your data (vault,
wallets, audit log, settings) lives in your Postgres service and is untouched
by a template redeploy to the app service alone.
Before redeploying:
- Read the changelog for the version you're moving to — check specifically
for anything marked security-critical or for any migration notes. (If a
dashboard UI isn't available to you yet,
GET /dashboard/template-updateswill return the changelog text andseverityfor your node directly.) - Confirm you don't have anything time-sensitive in flight (an active sweep,
consolidation, or outbound transfer) — a redeploy restarts the process,
which triggers the same crash-recovery pass described in
incidents.md. That pass is designed to handle an in-flight transfer safely, but there's no reason to create unnecessary work for it if you can just wait a few minutes for things to settle first. - After the redeploy, confirm
/health/readyreturns 200 and spot-check the admin dashboard loads normally before considering the update complete. - Re-register the node with the platform afterward if you want its recorded
template_versionto reflect the new version promptly (see the note above — there's no automatic re-poll yet).
What updating does not affect
A template update changes the application code your node runs. It does not:
- Rotate or touch any wallet key (see
key-rotation.mdfor why wallet keys never rotate at all). - Change your admin credentials or TOTP enrollment.
- Require re-registering with the hosted dashboard for the node to keep working — registration only affects whether the platform's recorded template version (and therefore the update-notification API above) is current; your node's identity (its discovery fingerprint) is stable across template versions either way.