Community

Apps

Python3 NWC Library

This is not a packaged Python SDK with releases, async helpers and a broad test matrix. It is a readable `nwc.py` implementation that shows how NWC requests are shaped, encrypted, signed and sent.

Python3 NWC Library visual
Python3 NWC Library icon
Apps The product layer Clients, signers, publishing tools, wallets and useful experiments.
Back to Nostr
Apps

Apps shelf

Apps pages collect clients, signers, tools, developer libraries and product research without turning the app into the whole network.

Apps30 min readSmall CC0 Python library for learning and scripting Nostr Wallet Connect client calls

Python3 NWC Library

This is not a packaged Python SDK with releases, async helpers and a broad test matrix. It is a readable `nwc.py` implementation that shows how NWC requests are shaped, encrypted, signed and sent.

The quick readPython3 NWC Library is the `supertestnet/python_nwc` repository: a small CC0 Python project whose README calls it a python3 library for working with Nostr Wallet Connect. As checked on June 15, 2026, the repository contained a README, LICENSE and one `nwc.py` file, with GitHub metadata showing Python as the language, four stars, two forks, no published releases and a latest push in July 2024. The code parses `nostr+walletconnect://` strings, derives an app public key from the secret, signs Nostr events, opens WebSocket relay connections and sends kind 23194 requests for `make_invoice`, `lookup_invoice`, `pay_invoice`, `get_info`, `list_transactions` and `get_balance`. It is useful when you want to understand the moving parts or build a controlled script. It should not be treated as a drop-in production SDK without review: the README asks you to install `websocket-client`, `secp256k1` and `pycryptodome==3.10.1`; the code uses NIP-04-style AES-CBC payloads rather than modern NIP-44 v2; it has no packaging metadata, no release tags, no visible test suite and limited timeout/error handling. Use it with disposable or tightly limited NWC credentials, compare behavior against the current NIP-47 spec, and verify wallet-service encryption support before putting real money behind it.

Start with the actual object

Python3 NWC Library is a small repository named `supertestnet/python_nwc`. Its README is blunt: it is a python3 library for working with Nostr Wallet Connect. That description is accurate, but it needs context before you decide how much trust to put in it.

The project is not a wallet, not a Nostr client, not a hosted service and not a polished package on the Python ecosystem shelf. The repository contains a README, a CC0 license and a single `nwc.py` file. There is no setup script, no `pyproject.toml`, no release history and no test directory visible in the repository checked on June 15, 2026.

That does not make it useless. It makes it a very specific artifact: a readable NWC client implementation for people who want to see how a Python script can parse a NWC URI, derive keys, sign Nostr events, encrypt wallet commands, speak WebSocket to a relay and ask a wallet service to create invoices, check invoices, send payments or report balance.

If you are a reader trying to choose tooling, the distinction matters. Use this library as source material, a prototype base or a lab script. Treat a production payment integration as a separate decision that requires current NIP-47 behavior, modern encryption support, dependency review, wallet-specific testing and operational guardrails.

Why it appears in the NWC map

The reason this project belongs in the Nostr apps hub is not popularity. It belongs because NWC needs more than wallet apps and web clients. It needs small language examples that show builders how the protocol looks without hiding every detail behind an SDK abstraction.

The NWC homepage presents Nostr Wallet Connect as a way for apps to connect Lightning wallets through Nostr relays. The NIP-47 spec describes a client, a wallet service, a connection URI, encrypted request events, encrypted response events and a relay sitting between them. Python3 NWC Library sits at the client side of that picture.

A Python developer may arrive here from a backend script, an automation job, an agent experiment, a command-line tool or a test harness. In that situation, a compact single-file implementation can be easier to inspect than a larger framework. You can read the function names and see the protocol verbs directly: `makeInvoice`, `checkInvoice`, `tryToPayInvoice`, `getInfo`, `listTx` and `getBalance`.

That simplicity is the value and the risk. A tiny file teaches the mechanics quickly. It also leaves many things to the caller: connection lifecycle, multiple relays, modern encryption negotiation, robust error handling, retries, logging hygiene, payment state, dependency pinning and secret storage.

Repository state checked today

GitHub metadata checked on June 15, 2026 showed `supertestnet/python_nwc` as a public, non-archived repository created on July 9, 2024. The default branch is `main`, the license is CC0-1.0, the language is Python, and the repository had four stars, two forks and no open issues in the API response.

The same metadata showed the latest push on July 24, 2024. The visible repository page reported 18 commits, no published releases and no packages. That combination should guide your expectations: this is not a versioned dependency with semantic releases and changelogs you can pin by release number.

The latest commits are also useful context. A July 24, 2024 pull request added methods and support for a payment hash in invoice lookup. The resulting surface includes `getInfo`, `listTx`, `getBalance` and a `checkInvoice` helper that can accept either a BOLT-11 invoice or a `payment_hash`.

Because there is no packaged release channel, the safest way to evaluate the project is to read the exact commit or raw file you plan to use. If a script imports a local copy of `nwc.py`, your real dependency is that copied file, not the moving GitHub branch name.

What the README tells you

The README is short, which is helpful. It names three dependencies: `websocket-client`, `secp256k1` and `pycryptodome==3.10.1`. It then explains their roles: WebSocket relay communication, secp256k1 key generation/signing and encrypted Nostr direct-message payload handling.

It also shows the expected flow. You call `processNWCstring` with a `nostr+walletconnect://` URI. Then you can call `makeInvoice` with an amount in sats and a description, `checkInvoice` with a BOLT-11 invoice, `didPaymentSucceed` to see whether a payment has a preimage, and `tryToPayInvoice` to send a payment request.

The README's explanation of `tryToPayInvoice` is one of the most important pieces of the project. Super Testnet says the JavaScript version originally used a method named `payInvoice`, but Lightning payments do not reliably finish quickly, and payments can sometimes get stuck for minutes or hours. The Python helper therefore sends the pay command and recommends checking later with `didPaymentSucceed`.

That is a useful mental model for readers. NWC does not magically turn Lightning into a synchronous database call. Your app still needs pending states, timeout behavior, user-visible status, idempotency thinking and a way to ask the wallet service what actually happened.

How the URI parser works

The code begins the practical flow with `processNWCstring`. It checks whether the string begins with `nostr+walletconnect://`, removes that prefix, splits the remaining string around query parameters and returns a dictionary containing the wallet public key, relay, app private key, optional Lightning address and derived app public key.

This maps to NIP-47's connection URI model. The wallet service gives the client a URI containing the wallet service public key in the base path, at least one relay parameter and a secret parameter that the client uses to sign events and encrypt payloads. The library turns that into a Python object its later functions can reuse.

The implementation is intentionally direct. It uses string splitting rather than a full URL parser. That means a reader should be careful with edge cases such as URL-encoded values, multiple relays, unexpected query ordering, duplicated parameters or connection URIs that rely on behavior beyond the simple examples.

For a controlled script, this may be enough. For a broader application that accepts user-pasted NWC strings from multiple wallet services, use a proper URL parser, preserve repeated relay parameters and validate every extracted value before storing it.

Nostr events under the hood

The file's `getSignedEvent` helper follows the basic Nostr event shape from NIP-01. It serializes the event data array, hashes it with SHA-256, and signs the event id with a Schnorr signature from the app private key. The resulting event carries `id`, `pubkey`, `created_at`, `kind`, `tags`, `content` and `sig`.

For NWC requests, the helper functions build events with kind `23194`. Each request tags the wallet service public key with a `p` tag and places the encrypted JSON command in `content`. The wallet service listens through the relay, decrypts the request, performs the wallet action if allowed and returns a kind `23195` response addressed back to the app public key.

That makes the library a useful teaching object because the protocol does not disappear. If `makeInvoice` fails, you can inspect whether event signing, relay submission, wallet-service support, encryption, method authorization or Lightning backend behavior is the likely source of the failure.

The same visibility matters when you compare it with nwcjs, Alby JS SDK or the NWC HTTP API. Those tools may give you a friendlier developer experience, but they still need to satisfy the same event and method contract.

The method helpers it exposes

`makeInvoice` sends a `make_invoice` request with an amount converted from sats to millisats and a description. The NWC reference docs describe `make_invoice` as a request for a BOLT-11 invoice and define fields such as amount, description, expiry, invoice, payment hash and payment state in the response shape.

`checkInvoice` sends `lookup_invoice`. The current code accepts either an invoice or a payment hash, matching the reference API's statement that one of `payment_hash` or `invoice` is required. `didPaymentSucceed` then wraps invoice lookup and treats a returned preimage as evidence that payment succeeded.

`tryToPayInvoice` sends `pay_invoice`. In the NWC docs, that method asks the wallet to pay a BOLT-11 invoice and can return a preimage when the wallet service reports success. In this Python file, the function sends the request and returns the request event id rather than waiting indefinitely for settlement.

`getInfo`, `listTx` and `getBalance` cover the read side. `get_info` asks for wallet-account information and supported methods, `list_transactions` asks for invoices/payments with filters, and `get_balance` asks for balance in millisats. Together, they make the file more than a single payment demo.

Encryption is the main compatibility question

The most important technical caveat is encryption. The library's `encrypt` and `decrypt` functions derive a shared key from secp256k1 ECDH and use AES-CBC with a 16-byte IV. The output shape is a base64 ciphertext plus an `?iv=` query-style suffix. That is recognizably NIP-04-style encrypted payload handling.

NIP-47 has moved toward encryption negotiation and modern NIP-44 v2 payloads. The current NIP-47 text says request and response content is encrypted with NIP-44, while also noting backwards compatibility for the initial NIP-04 version. It says that absent an encryption tag, a wallet may be assumed to support NIP-04, and that clients should choose NIP-44 when possible.

NIP-04 itself is marked unrecommended and its security warning is not cosmetic. NIP-44 v2 uses a different design with HKDF, ChaCha20, HMAC, padding and test vectors. That does not automatically mean every old NWC implementation is unusable, but it does mean you must check what your wallet service supports before relying on this file unchanged.

A practical approach is simple. Use this library against test credentials first. Call `get_info` or inspect the wallet service's info event. Check whether encryption tags and NIP-44 support are present. If the wallet expects NIP-44-only requests, this file's current AES-CBC path will not be enough without changes.

Relay behavior is deliberately simple

The `getEvents`, `sendEvent` and `getResponse` helpers use `websocket-client` to connect to a relay, send Nostr messages and wait briefly for response events. That is the right transport layer for NWC, because the protocol deliberately routes wallet requests through Nostr relays.

The implementation is also narrow. It keeps one relay string from the parsed connection object, opens WebSocket connections directly and uses small polling loops. It does not present a robust multi-relay strategy, a long-lived subscription manager, durable request tracking, exponential backoff or wallet-specific retry policy.

That matters because relays are not just neutral pipes. A relay may require authentication, drop events, rate-limit traffic, retain responses differently, block clients, have uneven uptime or behave differently across local and public network conditions. A script that works with one relay can fail with another for reasons unrelated to the wallet method.

If you build from this code, plan relay behavior explicitly. Decide whether the NWC URI may contain multiple relay parameters, whether you try them in order, how long you wait for kind `23195` responses, how you log relay errors without leaking secrets and what the user sees when the wallet service never replies.

Dependency and packaging risks

The README dependency line is easy to copy, but it deserves attention. `secp256k1` can involve native bindings and platform-specific install friction. `pycryptodome==3.10.1` is pinned to an old version. `websocket-client` is a mature library, but your relay behavior still depends on timeouts, TLS handling and network environment.

The repository does not publish a package, so installing the library is not a normal `pip install python-nwc-library` workflow. You either copy `nwc.py`, vendor the file, import from a cloned repository or create your own package wrapper. Each option changes how you track updates and security fixes.

For prototypes, copying a single file is often acceptable. For production, treat the copy as your own dependency. Record the commit, run dependency scans, test on your target operating systems, decide whether native `secp256k1` is acceptable, and document how a future NIP-47 encryption change will be handled.

This is also where Python-specific expectations matter. There are no type hints, no async API, no structured exceptions and no install metadata. If your app already uses `asyncio`, structured logging, dependency injection or a secrets vault, you will probably wrap or rewrite parts of the file rather than import it raw.

What it is good for

The library is good for reading. It compresses a full NWC client into a file you can inspect in one sitting. That is valuable if you are trying to understand how a NWC connection string turns into a signed Nostr event and how wallet method names become encrypted JSON payloads.

It is good for controlled scripts. A developer can create a low-value NWC connection in Alby Hub, Bankify or another compatible wallet service, then use the Python file to create a test invoice, check balance or observe response events through a relay.

It is good for comparison. If a higher-level tool fails, you can compare whether this direct implementation reaches the wallet service. If this file fails too, the problem may be relay access, wallet permissions, encryption mismatch or backend behavior. If this file works but your app fails, your app's wrapper may be the problem.

It is not good as an invisible high-trust money dependency unless you have done the engineering work around it. NWC credentials can authorize payment requests. A small script that stores a broad connection string in a plain environment file can still move real money if the wallet allows it.

The reader-facing decision is therefore not Python versus JavaScript or small file versus large package. The decision is whether you need an inspectable learning tool or an operational dependency. If you are trying to understand why a wallet service answers `lookup_invoice` one way and `get_balance` another way, this file is friendly. If you are building a public service where strangers paste wallet credentials, you need more ceremony: current encryption negotiation, release pinning, audits, tests, support expectations and a clear plan for what happens when a wallet refuses a method.

How to test it responsibly

Start with a disposable NWC connection. Give it a narrow method set and a tiny spend limit. If you only need invoice creation, do not grant outgoing payment authority. If you are testing `list_transactions`, assume you may expose payment history to your own logs and terminal scrollback.

Run `getInfo` first. Confirm which methods the wallet service says this connection can use. Then test a receive flow with `makeInvoice`, pay the invoice from another wallet, and use `checkInvoice` or `didPaymentSucceed` to observe state. Only after that should you test `tryToPayInvoice`, and only with an invoice you control.

Watch the units. NWC method parameters are commonly expressed in millisats, while the README example asks for sats and the code multiplies by 1000 in `makeInvoice`. Amountless invoices need explicit amount handling. A tiny unit mistake is annoying in testnet and expensive with a real wallet.

Finally, revoke or rotate the connection when the test is done. NWC's convenience comes from sustained app-to-wallet access. That sustained access is exactly why a pasted URI should be treated like a scoped wallet credential, not like a harmless public identifier.

Where it sits beside other NWC tools

Python3 NWC Library sits beside a small cluster of NWC developer tools. nwcjs is the sibling JavaScript implementation from Super Testnet. NWC Tester (Advanced) uses browser-side tooling to exercise NWC strings and method behavior. NWC Tester (Simple) is a smaller web check.

Alby JS SDK and the NWC HTTP API sit at a different level. They make it easier for web and server developers who want a maintained abstraction. The Python file is closer to a reference sketch: less ergonomic, more visible, easier to reason through line by line.

The NDK, Rust Nostr and other broader Nostr libraries solve adjacent problems around relays, event signing and protocol plumbing. Python3 NWC Library is narrower. It cares about NWC wallet calls, not the whole Nostr client stack.

That narrowness is why the page should be found from Developer Tools & Libraries rather than from wallet interfaces. A wallet user should not start here. A builder trying to understand Python-side NWC mechanics might.

The production checklist

Before using this code beyond a lab, freeze the exact commit. Read `nwc.py` yourself. Check whether your wallet service accepts NIP-04-style requests or requires NIP-44 v2. Decide how you will store the NWC URI, how you will rotate it and how you will prevent logs from printing the secret.

Then add the missing product behavior. Timeouts should be explicit. Errors should be structured. Relay failures should be distinguishable from wallet errors. Payment attempts should have pending states and follow-up lookup. Invoice creation should validate units. Transaction listing should avoid leaking history into analytics or debug output.

Test more than one wallet service if your app claims NWC compatibility. A script that works only against the author's example URI is not an integration. Compare with Alby Hub, Bankify, LNbits, Coinos or another service relevant to your users, and verify permission differences rather than assuming all wallets expose the same method set.

Most importantly, think like a wallet user. If someone gives your app a NWC URI, they are giving it scoped authority over money. The right developer experience is not just fewer lines of Python. It is predictable limits, visible status, revocable access and no surprises.

Bottom line

Python3 NWC Library is a useful small artifact because it makes Nostr Wallet Connect visible in Python. It shows the connection string, app key, relay event, encrypted method request and wallet response path in a form a curious developer can read without a framework.

Its limits are just as important as its usefulness. It is small, unversioned, NIP-04-style, lightly wrapped and not presented as a maintained production SDK. That is fine as long as you use it for the right job.

If you want to learn NWC or build a controlled prototype, it is worth opening. If you want to run real user money through a Python service, use it as a reference and then do the less glamorous work: current spec compatibility, modern encryption, dependency review, wallet-permission design, relay resilience, tests and secret handling.

That is the honest place for the project in the ecosystem. It lowers the barrier to understanding NWC. It does not remove the responsibility that comes with wallet automation.

Sources worth opening

Open the repository, README and raw `nwc.py` first. Then compare NIP-47, NIP-04, NIP-44 and the NWC reference API pages so the library's method helpers are understood as protocol messages with real wallet authority.

Back to the Crays Nostr page
Apps route visual cue 1
Apps route visual cue 2
Apps route visual cue 3
Apps route visual cue 4
Apps route visual cue 5

How to use this page

Keep the product map close.

Search the wider app shelf when you want another client, tool, protocol reference or source trail beside this page.

AppsBrowse Apps pagesApps pages stay availableProducts, tools, communities and source trails.Browse pages
Apps contribution visual cue 1
Apps contribution visual cue 2
Apps contribution visual cue 3
Apps contribution visual cue 4
Apps contribution visual cue 5

Bring something back

Ask, suggest, submit or nominate.

Ask a question, send a source, suggest a fix, submit a project or nominate a public Nostr account. The page stays stable; your contribution gets reviewed beside it.