ZapPlanner
ZapPlanner is a working recurring-payment experiment, not a generic wallet. It shows how NWC can let a user approve a repeating Lightning payment while keeping the actual wallet connection under the user's control.
ZapPlanner is a recurring payment tool
ZapPlanner does one thing that normal Lightning wallets still make awkward: it schedules payments that repeat. Instead of visiting a creator, publisher, donation page or service every time you want to send sats, you create a recurring payment with a recipient Lightning Address, an amount and a schedule. The app then uses a connected wallet to send future payments without making you manually approve each one.
That makes ZapPlanner a commerce and support tool, not a social client and not a wallet by itself. It does not hold your main wallet interface, host a Nostr feed, run a relay or act like an exchange. Its purpose is to coordinate a payment instruction over time. The user-facing surface is simple, but the trust model is deeper because a recurring payment needs permission to act after the first click.
The right way to understand it is as an NWC proof of usefulness. Nostr Wallet Connect is often explained as a protocol that lets apps request wallet actions through Nostr relays. ZapPlanner makes that concrete: an app can remember a schedule, fetch an invoice from a Lightning Address, and ask the user's wallet to pay it later under whatever limits the wallet connection allows.
The public trail points to Alby Labs
The live service runs at `zapplanner.albylabs.com`, the public repository lives under `getAlby/ZapPlanner`, and the Alby Hub user guide has a dedicated ZapPlanner page. Alby's wider Labs blog also presents ZapPlanner as part of a set of experiments around Lightning apps, alongside tools such as BuzzPay and PkgZap. This is not an anonymous one-page payment link with no operator trail.
The repository description is direct: scheduled recurring Lightning payments powered by Nostr Wallet Connect, enabling Lightning subscriptions and recurring Bitcoin payments. The app metadata says it schedules Lightning payments to a Lightning Address using NWC. The current repository has a visible Next.js, Prisma, Inngest, Nostr Tools, Alby SDK and Bitcoin Connect codebase rather than only a landing page.
There is also an important humility signal. The README calls ZapPlanner a hackday / Alby Labs project that shows how Lightning subscriptions can be possible through NWC. It says the architecture would need to be rethought for better reliability and scale. That sentence should stay in the reader's head. The project is real, but it is honest about being an experiment and a demonstrator, not a finished Stripe-scale billing system.
The normal user flow is intentionally small
The main ZapPlanner flow starts with a new recurring payment. The create page asks for a recipient Lightning Address, an amount and a frequency. Frequency can be expressed as hours, days, weeks or months, and the form also supports a cron-expression mode for more precise schedules. After that, the user confirms the payment details and connects a wallet.
The confirmation screen summarizes the amount, recipient, frequency, first payment time, optional message and optional payer data. The example public URL shows a 21-sat payment to `hello@getalby.com` every day, including a message and payer-data JSON. That is a useful detail because it shows ZapPlanner is not just a pretty button. It can receive prefilled payment plans from another service.
After the recurring payment is created, ZapPlanner gives the user a management page. The code shows support for email settings, payment notification preferences, cancellation, reactivation after failures, and a manual pay-again button for non-cron subscriptions. The page itself tells users to bookmark it or provide email so they can later cancel the recurring payment, and it also reminds them that deleting the NWC connection cancels the payment path from the wallet side.
Programmatic confirmation links are the hidden power
ZapPlanner is not only a form for humans. The README and live layout describe a programmatic confirmation URL that can prefill subscription details. A service can build a URL with `amount`, `recipient`, `timeframe` or `cron`, `comment`, `payerdata`, `returnUrl` and optionally `nwcUrl`, then send the user directly to a confirmation screen.
That matters because recurring payments become more interesting when they are embedded in another product. A podcast, publication, club, open-source project, media site or membership service could offer a recurring Lightning payment without building every scheduler and wallet-connection screen from scratch. The user still has to confirm, but the service can set the intended terms.
The README also says the API can be called by other services to set up subscriptions without visiting ZapPlanner, while noting that the API is currently undocumented. That is the difference between a promising demo and a mature platform. The capability exists in code and UI, but a production integrator should not depend on undocumented behavior without testing and pinning assumptions.
NWC is the heart of the trust model
Nostr Wallet Connect is what lets ZapPlanner act later. In NIP-47 terms, an app and a wallet communicate through encrypted events over Nostr relays. The wallet grants a connection string with enough information for the app to send permitted requests. In ZapPlanner's case, that connection is used by Alby's Nostr WebLN provider to pay invoices on schedule.
The app validates that the provided wallet URL starts with `nostrwalletconnect://` or `nostr+walletconnect://` and includes a `secret` parameter. That validation is simple, but it points at the key risk: ZapPlanner stores a secret-bearing connection string. The repository's Prisma schema marks `nostrWalletConnectUrl` with an encryption annotation, and the Prisma client installs `prisma-field-encryption` middleware.
You should still treat the connection as a live payment credential. If your wallet supports budgets, spending caps, allowed methods, expiration or per-app labels, use them. A recurring-payment app should not have unlimited authority. Its entire purpose is to perform future actions, so the wallet-side limit is the user's real safety rail.
Bitcoin Connect handles the wallet handoff
The confirmation form initializes `@getalby/bitcoin-connect-react` with an app name of ZapPlanner and a filter for NWC. When the user connects, the form pulls the Nostr Wallet Connect URL from the provider and places it into the subscription request. If an `nwcUrl` is already supplied in the confirmation URL, the form can skip the visible wallet-connect button and use that provided connection.
That design is convenient but deserves careful reading. A prefilled `nwcUrl` can make embedded flows smoother, but it also means a URL can carry a secret. Users and integrators should not paste such URLs into public chats, analytics tools, screenshots or logs. If a service includes an NWC URL in a confirmation link, it should treat the whole URL as sensitive.
Bitcoin Connect is the usability layer here, not the payment system itself. It helps the app obtain an NWC provider and connection from compatible wallets. The payment behavior still depends on the connected wallet, relay reachability, permissions, budget and the user's ability to revoke the connection later.
Scheduling is built around Inngest
ZapPlanner uses Inngest to power background jobs. When a subscription is created, the API stores the subscription and sends a `zap` event. The Inngest function named `Periodic Zap` loads the subscription, sends or skips the payment depending on timing rules, sleeps until the next scheduled execution, then sends another event to repeat the loop.
The function has cancellation handling through a `cancel` event matched by subscription ID. It also has safety checks for retry count and for events firing too early. For cron subscriptions, it skips the first immediate payment and waits for the scheduled cron execution. For non-cron subscriptions, it calculates the next payment from the stored sleep duration in milliseconds.
This is practical engineering, but it is also the part the README warns about. The authors say Next.js as a serverless platform is not the right tool for this architecture and that each subscription rescheduling itself is not the ideal model. For small recurring support flows, that may be fine. For a business that needs strong billing guarantees, it is a warning to test failure and recovery carefully.
The payment itself uses LNURL-pay
ZapPlanner does not ask the sender's wallet to pay a static invoice forever. Each scheduled run creates a fresh payment by using the recipient Lightning Address. The code constructs a `LightningAddress`, fetches its LNURL data, checks that `lnurlpData` exists, requests an invoice for the current satoshi amount, then sends that invoice through the NWC-backed WebLN provider.
This design is important because a Lightning invoice is normally one-time. Recurring payments need a way to get a new invoice every time. A Lightning Address provides that by exposing LNURL-pay metadata and invoice generation. ZapPlanner can also pass a comment if the recipient permits it, and it can pass payer data when the recipient's LNURL data supports payer-data fields.
The recipient side still matters. If the Lightning Address is down, has min/max amount limits, changes payer-data requirements, rejects comments, or points to a wallet with liquidity problems, ZapPlanner can fail even if the sender's wallet is fine. A recurring payment is a chain: scheduler, sender wallet, Nostr relay, recipient LNURL server, Lightning route and final wallet all have to cooperate.
Amounts can be sats or fiat-denominated
The create form defaults to sats, but the code supports additional currencies. If a subscription has a currency other than sats, the API checks Alby's rates endpoint and uses Alby Lightning Tools to convert the amount to a satoshi value at payment time. That makes ZapPlanner more flexible for users who think in USD, EUR or another displayed currency.
Fiat-denominated recurring payments have a hidden accounting consequence. The number of sats can change over time because the conversion happens when the scheduled payment is processed. That may be what a payer wants for a subscription-like commitment, but it is different from sending exactly 1,000 sats every week.
If you use ZapPlanner for creator support, decide which unit expresses your intention. Sats are simple and native. Fiat units are easier for a budget tied to local currency. Either way, the management page and email notifications should be checked so you understand what was sent, when it was sent and whether future payments follow the same logic.
Cron support makes it more than a timer
ZapPlanner supports ordinary intervals and cron expressions. The README gives examples such as weekly or monthly cron schedules, and the form links to crontab.guru for help. The create form also treats monthly payments specially by mapping the simple monthly option into a cron expression for once per month.
Cron support is useful for real subscriptions because not every recurring payment is simply every N hours. A user might want a payment on the first day of the month, every Monday, or a specific recurring calendar pattern. The current code uses `cron-parser` and contains recent commit history around monthly and Nth-day cron support, which shows the scheduling surface has received ongoing attention.
Cron also raises expectations. If you schedule money by calendar, you care about missed runs, duplicate runs, daylight saving quirks, timezone assumptions and recovery after outages. ZapPlanner has checks and retries, but users should test their exact pattern with small amounts before treating a cron schedule as a durable billing contract.
Retries and failures are part of the product
The Inngest function records successful and failed payments, retry count, last successful payment time and last failed payment time. If a payment fails, retry count increases. If a payment later succeeds after previous failures, the code can classify that as recovery and send a payment-recovered email. If retries exceed the maximum, the subscription is deactivated.
That behavior is more useful than a silent scheduler. Recurring payments fail in ordinary ways: the sender wallet is offline, the NWC relay is unreachable, the recipient Lightning Address fails, the route cannot be found, the wallet budget is exhausted, or the connected wallet was revoked. A payment scheduler needs to surface those failures or users will assume support is flowing when it stopped.
The email path is optional and constrained. The UI says individual payment email confirmations are only supported for timeframes of one hour or more unless development flags override that. Users should therefore keep the management URL and not rely on email alone. The code itself tells readers to bookmark the page or provide email so cancellation remains available later.
Cancellation has two layers
ZapPlanner can cancel a subscription from its own management page. The delete API sends a `cancel` event to Inngest and then deletes the subscription from the database. That stops the scheduler from continuing through ZapPlanner's own job system.
The wallet has a second cancellation layer. The subscription page tells users they can delete the NWC connection to cancel the recurring payment. This is the stronger safety habit. If the app-side scheduler fails to delete, the wallet-side connection can still remove the app's authority. If the wallet connection remains broad and active, the app-side UI is not the only control that matters.
A careful user should test both. Create a tiny recurring payment, cancel it in ZapPlanner, then verify no further payment happens. Recreate a tiny payment, revoke the NWC connection in the wallet, then verify ZapPlanner fails clearly. A recurring payment tool is only comfortable when the exit path is as understandable as the setup path.
The architecture stores sensitive data
The Prisma model stores recipient Lightning Address, amount, currency, message, payer data, timing fields, counters, email settings and the encrypted NWC connection URL. That is the minimum record a scheduler needs, but it is also a sensitive operational footprint. A recurring payment is not just a transaction; it is a pattern over time.
The code uses `prisma-field-encryption` for the NWC URL, which is the right direction. Still, encryption depends on key management, deployment practices, logging discipline and access control around the database. The environment example includes `PRISMA_FIELD_ENCRYPTION_KEY`, database URL, email settings, Inngest keys, Sentry DSNs and defaults for development connections.
Users do not need to read every line of code to understand the lesson. If you create a recurring payment, ZapPlanner has enough data to attempt future payments and optionally email you about them. Use a dedicated NWC connection, avoid over-sharing payer data, and remember that your payment schedule itself can reveal relationships and habits.
Payer data and comments should stay modest
ZapPlanner can pass `comment` and `payerdata` to the recipient Lightning Address when the recipient supports those fields. The README points to LUD-18 for payer data, and the code only sends comments when the recipient LNURL metadata allows a comment of that length. This is useful for reference numbers, donation notes or lightweight identity fields.
It is also a place to avoid oversharing. A recurring support payment does not usually need private personal data. If a recipient asks for payer data, understand what is required and what is optional. Once data is embedded in payment-related systems, it can appear in logs, email notifications, dashboards or exports.
For developers embedding ZapPlanner links, use stable internal references rather than sensitive text. A `returnUrl` can bring users back to your site, and `comment` or payer data can carry a small reference. Keep it boring. The more personal the metadata, the more the payment scheduler becomes a privacy system.
ZapPlanner is closest to support and subscriptions
The cleanest use case is regular support. You want to send 100 sats every hour, 1,000 sats per day, or a monthly amount to a publisher, creator, open-source maintainer, community project or personal donation address. ZapPlanner gives you a way to make that support habitual without handing the recipient a card or bank mandate.
The second use case is subscription-like checkout. The README imagines third-party platforms using ZapPlanner behind the scenes, with a user connecting a wallet once and confirming a subscription. That resembles PayPal or card subscriptions in user shape, but the credential is an NWC connection with wallet-side budgets instead of a credit card number.
The tradeoff is flexibility. The README notes that push subscriptions from ZapPlanner make flexible charging harder, and that for some services it may be better for the service to access the NWC connection directly within user-set budgets. That is a serious architecture question. ZapPlanner is best when the amount and schedule are clear.
Alby Hub makes the idea easier to reach
ZapPlanner appears in Alby Hub's app-connection guidance, and Alby public posts and release notes continue to mention the app around Hub workflows. That matters because Alby Hub is one of the most visible ways ordinary NWC users create app connections. A recurring-payment tool is much less useful if users have to invent the wallet setup from scratch.
This does not mean ZapPlanner only works in one wallet environment. NWC is an open protocol pattern, and the app uses Nostr WebLN rather than an Alby account balance as the core concept. The practical compatibility question is whether your wallet can create a connection that permits the payment requests ZapPlanner needs and lets you cap or revoke that connection later.
For many readers, Alby Hub will be the most natural test path. Create a small wallet budget, connect ZapPlanner, schedule a tiny payment, then inspect Hub's app connection record. If you cannot understand what ZapPlanner can do from the wallet side, do not increase the budget.
Reliability is the main limit
ZapPlanner's strongest limitation is not conceptual. The concept is clear. The limit is operational reliability. A recurring payment tool has to wake up on time, fetch a fresh invoice, route a payment, update counters, send notifications, reschedule correctly and avoid double-paying. That is a lot of moving parts for any small app.
The README is unusually candid. It says the architecture would need to be rethought to become more reliable and scalable, that Next.js as a serverless platform is not the right tool, and that each subscription rescheduling itself does not really make sense as the long-term design. Those are not reasons to dismiss the project. They are reasons to size usage correctly.
Use ZapPlanner for bounded recurring support, experiments, demos and small amounts you can monitor. Be cautious before using it for critical bills, payroll, high-value subscriptions or obligations where a missed or duplicate payment causes real harm. Automation is convenient precisely because it fades into the background; that is why monitoring matters.
Security starts with the wallet budget
The safest ZapPlanner setup starts inside the wallet, not inside the web form. Create a dedicated NWC connection with a name you recognize, a tight monthly budget, an expiration if available, and the narrowest permissions your wallet supports. Use a wallet balance that matches the risk you are willing to automate.
Then create the recurring payment. Pay attention to amount, unit, frequency, first payment time, recipient Lightning Address and message. If you are testing a third-party prefilled confirmation link, inspect the full URL before connecting. A link can carry an amount, recipient, schedule, return URL, payer data and even an NWC URL. That is too much to approve casually.
After setup, save the management page and test revocation. You should know how to cancel from ZapPlanner, how to revoke from the wallet, and how failed payments are reported. If the payment is important, use email notifications and occasionally verify the recipient actually received the sats.
What developers should learn from it
ZapPlanner is valuable even if you never use it as your own scheduler because it demonstrates a full NWC payment loop. It shows a web app receiving subscription terms, obtaining an NWC connection through Bitcoin Connect, storing the connection, scheduling background jobs, requesting LNURL-pay invoices and paying them through an NWC-backed WebLN provider.
It also shows the awkward parts. Secrets need encryption. Schedules need durable workers. Cron needs validation. LNURL recipients need amount checks. Wallets need budgets. Failed payments need counters and email. Cancellation needs both app-side and wallet-side controls. None of that disappears because NWC makes wallet communication elegant.
For a developer building subscription payments, ZapPlanner is a map of the questions to answer. Do you want push payments controlled by your scheduler, or a service that requests payment from a user's wallet inside a budget? Who stores the NWC secret? Who owns retries? What happens when the wallet is offline? What evidence does the customer see after each payment?
How to test it responsibly
Start with a tiny amount and a recipient address you control. Use sats first so you can reason about exact amounts. Create a one-hour or one-day recurring payment, connect a dedicated NWC wallet connection, and watch the first payment. Check the wallet history, ZapPlanner management page and email notification if enabled.
Then test the unhappy path. Revoke the wallet connection. Lower the wallet budget. Use a Lightning Address with an amount limit. Cancel the subscription. Reactivate a failed subscription if appropriate. Look for clear status changes and make sure the app does not keep paying after you thought you stopped it.
If you plan to embed ZapPlanner confirmation links in another service, test URL encoding, `returnUrl`, comments, payer data, cron expressions and the unsupported API boundary. Keep logs out of secret-bearing URLs. A link that includes `nwcUrl` should be treated as a credential, not as harmless analytics data.
The practical verdict
ZapPlanner is one of the clearest examples of why Nostr Wallet Connect matters beyond zaps. It lets a user grant a bounded wallet connection to an app that performs future payments on a schedule. That is a real new shape for Lightning: recurring support and subscription-like flows without handing a platform a card or a custodial balance.
Its maturity should be read carefully. The app is public, open source, associated with Alby Labs and actively understandable from code. It is also explicitly described by its maintainers as a hackday / Labs project whose architecture needs work for reliability and scale. That combination is not a contradiction. It is an honest experimental tool.
Use ZapPlanner when you want small, understandable recurring Lightning payments and you are willing to manage wallet permissions. Be cautious when the payment matters enough that failure, duplication, privacy leakage or forgotten cancellation would hurt. In recurring payments, the most important feature is not starting. It is knowing how to stop.
Sources worth opening
Open ZapPlanner's live app, GitHub repository and Alby guide first, then compare the NWC, LNURL, scheduling and implementation sources before trusting it with recurring payments.
- ZapPlanner live app
- ZapPlanner how it works page
- ZapPlanner new recurring payment page
- ZapPlanner example confirmation page
- getAlby/ZapPlanner GitHub repository
- ZapPlanner README
- ZapPlanner package.json
- ZapPlanner Prisma schema
- ZapPlanner Inngest payment worker
- ZapPlanner subscription API
- ZapPlanner confirmation form code
- Alby Hub ZapPlanner guide
- Alby Labs blog mentioning ZapPlanner
- getAlby awesome-nwc list
- No Bullshit Bitcoin ZapPlanner article
- The Bitcoin Manual ZapPlanner article
- 21ideas recurring Lightning payments guide
- Nodesignal ZapPlanner Dauerauftrag guide
- Nostr Wallet Connect official site
- Nostr Wallet Connect documentation
- Alby NWC API guide
- NIP-47 Nostr Wallet Connect specification
- Bitcoin Connect repository
- Alby JavaScript SDK repository
- Inngest documentation
- Prisma field encryption package
- LNURL LUD-06 pay request specification
- LNURL LUD-18 payer data specification
- ms npm package used for timeframe parsing
- crontab.guru cron helper





