ZapGram
ZapGram is not just a Telegram command wrapper around NWC. Its code shows two wallet paths: an internal bot wallet backed by LNbits user wallets, and an external NWC wallet path for users who want payments to come from their own wallet connection. That makes it useful, but it also changes the custody and permission story.
What ZapGram really is
ZapGram is a Telegram Lightning wallet and payment bot. The public Telegram page names the bot `ZapGram`, lists the handle `@zap_gram_bot`, and describes it as a Bitcoin Lightning wallet in Telegram. The GitHub repository uses the same description and links back to the Telegram bot as the live app.
That sounds simple, but the code gives it a sharper shape. ZapGram is a TypeScript bot built with grammY, conversations, Fluent translations, Drizzle and SQLite. It talks to LNbits for internal user wallets and to Nostr Wallet Connect for external wallets. It can show a wallet screen, create Lightning invoices, pay BOLT11 invoices, send sats to Telegram users, accept group tips and manage paid access to private chats.
That makes ZapGram different from ThunderTip. ThunderTip is primarily a non-custodial payment coordinator where a sender wallet pays a receiver wallet through NWC. ZapGram has an internal wallet path too. Its own English start message explains two types of wallets: an internal wallet where bitcoin is stored on the service's servers, and an external wallet connected through Nostr Wallet Connect.
For a reader, that distinction is the page. ZapGram can be convenient because it puts small Lightning actions inside Telegram, where many Bitcoin communities already live. It can also be risky if a user assumes every action is non-custodial. Internal balances and NWC permissions are different trust models, and a good user needs to know which one is active before tapping a button.
The two wallet modes
The internal wallet mode is backed by LNbits. The source has a `MasterWallet` class that can create LNbits users, fetch a user's wallet, create invoices and pay invoices through LNbits APIs. The service layer creates an LNbits user by the Telegram user id when needed, gets that user's wallet, and wraps it as a ZapGram `UserWallet`.
The bot text is unusually direct about this. It says the internal wallet stores bitcoin on the service's servers and allows transfers inside Telegram without normal Lightning routing fees. In the source, an internal transfer creates an invoice for the recipient's LNbits wallet and pays it from the sender's LNbits wallet after checking balance.
The external wallet mode is the NWC path. A user enters a `nostr+walletconnect://...` URI in a private chat, ZapGram validates it by asking the connected wallet for balance, and then stores the URI on the user row. When a user later creates an invoice, pays an invoice or sends sats, the bot can ask whether to use the internal wallet or the NWC wallet.
This is useful because it lets casual users begin with a Telegram-native balance while more careful users can keep funds in an external wallet. It is also the source of confusion. The same bot screen can show a ZapGram balance and an NWC balance. One is a service balance on LNbits infrastructure; the other is a remote wallet controlled through a revocable NWC connection.
The NWC implementation
ZapGram's NWC code is small and readable. The `NostrWallet` class imports `nwc` from `@getalby/sdk`, creates a new `nwc.NWCClient` from the stored connection URI, and exposes methods for balance, invoice creation, invoice lookup and invoice payment. Those map directly to NWC methods a wallet service may support.
The balance call returns millisatoshis. Invoice creation calls `makeInvoice` with amount, description and expiry. Payment calls `payInvoice`, and after some error cases the code attempts a lookup because some wallets may not return a clean success response even when the invoice is paid. The implementation also treats several NWC timeout and response-validation errors as unknown payment status cases.
That is the right kind of caution. In Lightning software, a payment request can time out, the wallet may still pay, a wallet may return an implementation-specific error, or an invoice may already be paid. ZapGram's error layer exposes messages such as NWC connection failed, NWC timeout, no NWC answer, payment failed, insufficient funds and invoice already paid.
NWC does not mean ZapGram receives your Nostr social identity. NIP-47 describes a connection URI with relays, wallet service pubkey and a client secret used to send encrypted request events. It is a wallet authorization channel. In ZapGram, Telegram is the user interface, LNbits can be the internal wallet backend, and NWC is the optional external wallet control rail.
Connecting an external wallet
The connection flow happens only in private chat. The conversation handler sends a prompt asking for the NWC URL, waits for text matching `nostr+walletconnect:`, deletes the message containing the URL, validates the connection by calling `getBalance`, stores the URL on the user, creates a local `NostrWallet` object and returns the user to the wallet screen.
That private-chat design is important because the NWC URI is not a public address. It is an authorization string. Anyone who receives a usable connection URI may be able to ask the wallet for actions allowed by that connection. A Telegram bot should never invite users to paste that string into a group.
The English settings text explains the operational requirement too: an NWC-connected wallet must stay online for stable payments. If the connected wallet is unavailable during a payment, the transaction can fail. That is a common NWC reality. A phone wallet, a home node bridge or a cloud wallet service can each have different uptime behavior.
The practical setup is therefore simple. Create a dedicated NWC connection just for ZapGram. Set a tiny spend budget. Add an expiration if the wallet supports it. Give it only the methods you need. Revoke it after testing, after leaving a group, after sharing a screenshot by mistake, or any time the bot behaves differently from what you expected.
What users see in Telegram
The visible bot flow is designed around a wallet menu. The bot registers private-chat commands for `/start`, `/help`, `/wallet`, `/settings`, `/chats` and `/subscriptions`. It also responds to ordinary private messages by showing the wallet screen. The English locale describes ZapGram as a Lightning wallet for sending and receiving bitcoin in Telegram chats and paying or accepting Lightning payments worldwide.
The wallet message shows internal balance by default. If an NWC wallet is connected, it shows two balances: ZapGram and NWC. The wallet keyboard includes actions for sending to a user, paying an invoice, creating an invoice, connecting or disconnecting NWC, toggling group tip behavior and opening group or channel settings.
When a user pays or creates an invoice and an NWC wallet is connected, the bot asks which wallet to use. If the user chooses internal, the action goes through the LNbits-backed service wallet. If the user chooses NWC, the action goes through the connected external wallet. If no NWC wallet is connected, the helper returns internal automatically.
This is good product design because it keeps the main path short while leaving the custody choice visible. It is also a reason to slow down. If you are using the bot as a wallet, check the selected wallet before sending. A Telegram payment that feels like one button may be spending from a service balance or from your external wallet connection.
Invoices and QR codes
ZapGram can create Lightning invoices from either wallet mode. The invoice conversation asks for wallet choice, amount and optional memo. If the internal wallet is selected, ZapGram asks the user's LNbits wallet to create the invoice, stores a pending invoice record with payment request, payment hash, user id and expiry, then returns the BOLT11 invoice.
If the NWC wallet is selected, ZapGram asks the external wallet to make the invoice. In that case the external wallet owns the incoming payment state. The bot does not create a local pending-invoice row for that NWC-created invoice because the invoice belongs to the connected wallet service.
The user experience is friendlier than a raw invoice string. ZapGram decodes the invoice, builds a QR code, and replies with a photo caption containing amount, optional description, expiration and the invoice. That is useful in Telegram because the recipient can forward, scan or copy without leaving the chat context.
The risk is normal invoice risk. A QR code makes paying easy, but it does not prove the payer understands which wallet receives the money. If you generate an internal ZapGram invoice, you are receiving into the service balance. If you generate an NWC invoice, you are receiving into the external wallet. Test both modes with tiny amounts before using them casually.
Paying invoices
The invoice payment flow begins when the user chooses the pay-invoice action or sends a message containing a BOLT11 invoice. ZapGram decodes the invoice, asks which wallet to use when NWC is available, shows an invoice review step, and then pays through either the internal LNbits wallet or the external NWC wallet.
For internal payment, the user wallet calls the LNbits payment endpoint and converts LNbits errors into user-facing cases such as insufficient funds or already paid. For NWC payment, ZapGram calls `payInvoice` on the connected NWC client and then looks up the invoice to calculate fees paid. The success message reports amount, fee and total in sats.
The code also checks whether the paid invoice is one of ZapGram's own pending internal invoices. If it is, the bot deletes the pending invoice record and notifies the recipient that the invoice was paid. That lets internal invoice creation and internal or external payment meet cleanly inside Telegram.
The practical reading is that ZapGram is a real wallet surface, not only a tip shortcut. It handles BOLT11 invoices, QR creation, fee reporting, pending invoice notification and wallet choice. That is powerful enough to deserve wallet-level caution, even if most users only use it for small Telegram payments.
Sending to Telegram users
ZapGram can send sats directly to another Telegram user known to the bot. The sending conversation asks for a recipient, amount and wallet choice. Internal mode performs an internal LNbits transfer between two ZapGram user wallets. NWC mode creates an invoice for the recipient's internal ZapGram wallet and asks the sender's connected external wallet to pay it.
That design explains a subtle product boundary. Even when the sender pays from an external NWC wallet, the receiver side in this user-to-user flow is still a ZapGram internal wallet. The external wallet is used to fund the payment; the Telegram user receives into their ZapGram balance unless a different flow is used.
The code lowercases stored usernames and can look users up by username. That is convenient, but Telegram usernames are not a cryptographic identity layer. A username can change. A person may not have started the bot. The bot can know a Telegram id from a reply or from prior interaction, but a public handle alone should not be treated like a long-term payment key.
For small social payments, that may be fine. For larger transfers, ask the receiver to confirm, test with a tiny amount, and check which balance received the payment. ZapGram's strength is quick Telegram-native settlement, not formal identity assurance.
Group tips
ZapGram's group tip command is specific. In group or supergroup chats, the bot listens for `/tip` or `@zap_gram_bot`, optionally followed by an amount and username. If no amount is provided, the code defaults to 21 sats. The bot deletes the command message when it can, then posts a cleaner confirmation message.
The command can target a named Telegram user, the author of a replied-to message, or the chat creator in certain no-recipient cases. The bot refuses tips to yourself and refuses bot or Telegram service accounts. The English help text documents examples such as `/tip`, `/tip 100`, reply plus `/tip`, `/tip @user` and `/tip 50 @user`.
The funding path depends on the sender's settings. A user row has an `nwcTips` boolean. If group NWC tips are enabled and the sender has a connected NWC wallet, the bot creates an invoice for the recipient's internal ZapGram wallet and asks the sender's NWC wallet to pay it. Otherwise, it performs an internal transfer from the sender's ZapGram balance.
That makes ZapGram useful in Telegram communities, but it also means a group admin should explain the mode. A person saying `/tip 100` may be spending from their ZapGram balance or from an external wallet connection. The bot should be tested in a small group before it becomes a habit in a busy channel.
Paid chat access
ZapGram is more than a tip bot. The code includes chat records, subscription records, subscription payments, cron jobs for expiration and renewal, and handlers for private chat join requests. The English start message says users can add the bot to a chat with invite and user-blocking permissions to create paid access with one-time payment or monthly subscription.
That feature sits outside the narrow NWC-tip story, but it matters for risk. A paid-access bot needs Telegram admin rights, invitation control, ban or block permissions, payment records and renewal timing. It is not only moving sats between friends; it can become a gatekeeper for private community access.
The source models support one-time and monthly payment types, per-chat price, auto-renewal, expiration notification and subscription invoices. The locale strings say monthly subscriptions can be automatically debited from the ZapGram wallet, with `/subscriptions` used for control. Users should understand that auto-renewal is a spending rule, not just a reminder.
If you run a paid Telegram group, test this in a separate chat before depending on it. Confirm what happens when a payment fails, a subscription expires, a bot loses admin rights, a user changes username, a channel title changes, or the LNbits backend is unavailable. Paid access combines money and moderation, so failure messages matter.
Custody and operator risk
The internal wallet is the largest trust difference between ZapGram and a purely NWC-only bot. ZapGram's own English text says internal wallet funds are stored on the service's servers. The code confirms a server-side LNbits setup with admin keys, fee collection invoice key, bearer token support, user creation and wallet fetching.
That does not automatically make ZapGram bad. Custodial or semi-custodial balances can make tiny social transfers smoother, especially when many users are not ready to run a wallet or keep an NWC service online. But it does mean the operator, LNbits instance, database, server secrets and backups become part of the money path.
The required configuration includes bot token, webhook secret, database URL, LNbits URL, LNbits admin key, LNbits admin id, fee collection invoice key and host settings. Those are serious secrets. If a deployment is compromised, the risk is not only chat spam. Internal balances, pending invoices, payment records and bot authority may be exposed.
Use the internal wallet like you would use any small hosted Lightning service: keep balances small, withdraw when finished, do not treat it as savings, and verify the operator before relying on it. If you prefer self-custody, use an external wallet through NWC with tight limits and keep only dust-level balance inside the bot.
Telegram identity and privacy
ZapGram maps payments to Telegram users because Telegram is the product surface. The database stores Telegram user id as the primary id, username, first name, language code, NWC flag and NWC URL. That is practical, and it lets a group command refer to a username or replied message.
It is not the same as a Nostr public key or a Lightning node identity. Telegram controls the platform. Usernames can change. The bot sees Telegram ids and chat context. Group tips create visible social signals. Paid access can reveal membership and payment relationships. None of that is solved by NWC encryption between app and wallet service.
NIP-47 is still useful for privacy because the wallet connection can use unique keys per client and encrypted events over relays rather than exposing a main user key. But the surrounding app still has metadata. ZapGram knows the Telegram account, command timing and selected wallet mode. The external wallet knows invoices and payments. Telegram sees the chat environment.
For ordinary small tips, this is acceptable for many communities. For sensitive groups, treat the bot as a payment and membership service with metadata. Do not assume a Telegram bot becomes private because one part of the wallet protocol uses encrypted Nostr events.
How to test ZapGram safely
Start in a private chat with `@zap_gram_bot` from the official Telegram link in the repository or NWC app list. Open `/wallet`, read the balances shown, and avoid depositing meaningful funds before you understand the internal wallet. If you connect NWC, create a dedicated low-limit connection and paste it only into the private bot chat.
Test invoice creation in both modes if you use both. Create a tiny internal invoice and pay it from a separate wallet. Then connect a tiny NWC connection, create an NWC invoice, and confirm that the money lands in the external wallet rather than the internal ZapGram balance. These two tests teach the user interface better than any label can.
Test outbound payments next. Pay a tiny external BOLT11 invoice from the internal wallet. Then pay one from NWC and confirm the wallet-side prompt or balance change. Watch the fee reporting. If an NWC payment times out, check the external wallet before retrying, because the code itself treats unknown payment status as a real possibility.
Finally test a small group. Add the bot to a throwaway Telegram group, tip a reply with the default 21 sats, tip a username, toggle NWC tips, and remove the bot. If you plan to use paid access, create a separate test chat and run the whole join, pay, expire and remove cycle before pointing real members at it.
How it fits the NWC map
ZapGram belongs in the NWC ecosystem because it is listed by getAlby's awesome-nwc project under tipping bots and because its source directly uses Nostr Wallet Connect through the Alby SDK. It also appears in NWC-focused app lists and community guides as a Telegram Lightning wallet that can connect external wallets.
It should not be described as a Nostr social app. ZapGram does not replace Damus, Amethyst, Primal or noStrudel. A user is not posting Nostr notes through ZapGram. The Nostr part is the wallet authorization protocol, not a public social feed.
It also should not be flattened into the same sentence as every other tip bot. ThunderTip is more purely an NWC payment coordinator. Zap Bot is a Discord-facing MakePrisms service. ZapGram is a Telegram wallet surface with internal LNbits balances and optional external NWC payments. The category is shared, but the architecture is different.
That architecture is interesting because it shows the messy middle of adoption. People want a simple Telegram wallet. Some want to keep funds in the bot for convenience. Others want external wallet control through NWC. ZapGram tries to serve both, and the reader's job is to choose the mode intentionally.
The bottom line
ZapGram is a useful and unusually concrete NWC-era app because it does not hide in protocol talk. It puts Lightning payments into Telegram, where users can send to people, pay invoices, create QR invoices, tip group messages and manage paid chat access from a familiar chat interface.
The same concreteness is why it needs a careful page. ZapGram is not one custody model. Its internal wallet is service-hosted through LNbits, and its external wallet mode uses NWC to request actions from a user's own wallet. Those are different risks. A user who confuses them can make bad decisions with real sats.
The strongest way to use ZapGram is with small amounts, clear labels and deliberate wallet choice. Keep internal balances low. Use dedicated NWC connections with low budgets. Revoke connections when done. Test invoices and group tips before making the bot part of a community habit.
If you read ZapGram as a Telegram-native Lightning wallet with optional NWC rather than as a generic Nostr app, it makes sense. The bot is promising because it meets people inside a chat app. It is safe enough to explore when the amounts are tiny, the operator is understood and the wallet permissions stay narrow.
Sources worth opening
Open the Telegram bot profile and GitHub repository first, then read the NWC source file, LNbits wallet files, bot command handlers, English locale strings, schema and NIP-47. The Stacker News guide is useful as a user-flow snapshot, but the code is the stronger evidence.
- ZapGram Telegram bot profile
- ZapGram Telegram preview image
- ZapGram GitHub repository
- ZapGram GitHub API metadata
- ZapGram repository tree
- ZapGram README
- ZapGram package file
- ZapGram bot entry source
- ZapGram NostrWallet source
- ZapGram LNbits user wallet source
- ZapGram LNbits master wallet source
- ZapGram LNbits service source
- ZapGram database schema
- ZapGram NWC connection conversation
- ZapGram invoice creation conversation
- ZapGram invoice payment conversation
- ZapGram send-to-user conversation
- ZapGram group tip command
- ZapGram wallet message helper
- ZapGram English locale
- ZapGram config source
- getAlby awesome-nwc
- getAlby awesome-nwc raw README
- Nostr Wallet Connect site
- Nostr Wallet Connect docs
- NIP-47 raw markdown
- Telegram Bot API
- Telegram bot features
- grammY bot framework
- grammY conversations plugin
- LNbits wallet documentation
- Stacker News ZapGram guide
- Nostr.com NWC profile
- Damus mirror of NWC Telegram bots note
- 21ideas ZapGram guide
- 21ideas Lightning tools page
- Bitcoin Review episode 93
- Buho connections app store





