Community

Relays

NWCLay

NWCLay is a focused relay for Nostr Wallet Connect. It narrows event kinds, filters and retention around NWC traffic, so the real question is whether a wallet service and client can depend on that relay without mistaking it for a wallet or a broad public relay.

strfry visual
NWCLay icon
Relays Network infrastructure Relays, relay tools, moderation policy, search and availability.
Back to Nostr
Relays

Relays shelf

Relay pages cover the servers, filters, management tools, monitoring services and policy choices that make Nostr usable at scale.

Relays26 min readNostr Wallet Connect relay infrastructure, NIP-47 event filtering, short retention, Docker deployment and wallet-service delivery checks

NWCLay

NWCLay is a focused relay for Nostr Wallet Connect. It narrows event kinds, filters and retention around NWC traffic, so the real question is whether a wallet service and client can depend on that relay without mistaking it for a wallet or a broad public relay.

The quick readNWCLay is not a wallet, not a Lightning node and not a general Nostr timeline relay. It is a domain-specific relay implementation inside the dezh-tech DDSR repository. The live relay at `wss://nwclay.paywithflash.com` advertises the name `nwclay.paywithflash.com`, the description `Only accepts NWC events`, contact through PayWithFlash and software from `github.com/dezh-tech/ddsr`. Its NIP-11 response currently reports supported NIPs 1, 47 and 9 with version `NWClay - 1.0.0`, while the repository code currently exposes version `NWClay - 1.1.1` and sets supported NIPs 1 and 47. The code accepts only NWC-related kinds 13194, 23194, 23195 and 23196, requires precise filters with authors, `#p` or `#e`, rejects count filters and keeps most traffic only briefly for delivery reliability. Use it when you want a relay path focused on Nostr Wallet Connect messages. Before relying on it, check the live NIP-11 document, the event kinds your wallet service actually emits, notification support, retention window, relay URL in the NWC connection string, time sync, websocket behavior and how your app handles rejects or delayed responses.

A relay with a very narrow job

NWCLay is a Nostr relay, but it should not be read like the broad relays people use for timelines, profiles, notes, reactions and lists. Its live relay page says the thing plainly: it only accepts NWC events. The README in the dezh-tech DDSR repository says the same thing and frames NWCLay as a relay that accepts only Nostr Wallet Connect traffic.

That narrowness is the product. A normal relay has to make policy decisions for many kinds of events. NWCLay makes a stronger promise: it is built around the message shapes that NWC wallet services and client apps need. If you send ordinary social notes to it, you should expect rejection. If you ask it for broad relay behavior, you are using the wrong tool.

For readers, this matters because NWC traffic sits near payment capability. The relay does not hold the wallet and it does not pay invoices. But it does carry encrypted requests, responses and wallet-service information between the app and the wallet service. That makes delivery, filtering, timing and metadata more important than they look from the outside.

NWCLay belongs in the relay shelf because it is transport infrastructure. It appears in the Apps hub because every project in the ecosystem map needs to be findable there. The article itself should keep the boundary clear: the wallet service decides what payments are allowed; NWCLay decides which Nostr events it will carry.

The live relay signal

The live deployment checked for this article is `wss://nwclay.paywithflash.com`. Opening the same host as a web page shows `nwclay.paywithflash.com`, the description `Only accepts NWC events`, a relay pubkey, a PayWithFlash contact link, the software name NWCLay and supported NIPs displayed on the page.

Fetching the host with the NIP-11 accept header gives the more useful machine-readable document. It reports the name `nwclay.paywithflash.com`, description `Only accepts NWC events`, contact `https://paywithflash.com`, supported NIPs 1, 47 and 9, software `https://github.com/dezh-tech/ddsr`, version `NWClay - 1.0.0`, plus icon and banner URLs.

That live document is the first thing a serious user should check because it describes the relay you are actually connecting to, not only the code you hope is deployed. In this case, there is a small but important version detail: the repository now contains version constants for `NWClay - 1.1.1`, while the live relay reports `NWClay - 1.0.0`.

That mismatch is not automatically alarming. Hosted services often lag a repository or pin a stable image. It is still operationally relevant. If your app depends on a behavior added after 1.0.0, the live relay may not have it. Always test the live endpoint you intend to put in the NWC connection string.

Where NWCLay comes from

NWCLay lives inside the `dezh-tech/ddsr` GitHub repository. DDSR means Domain-Specific Relays, and the parent README describes the repository as a set of Nostr relays for specific purposes based on Khatru, Event Store, Blob Store and Go Nostr.

That parent context is useful. NWCLay is not an isolated hosted trick. It is one relay in a small family of specialized relays. The repository is written in Go, carries an MIT license and uses Nostr relay building blocks rather than a one-off closed implementation.

The repository metadata checked for this article showed the project created in January 2025, updated later in 2025, written primarily in Go, published under MIT and tagged around Nostr, relays, Khatru, Blossom and domain-specific relay work. Those signals do not prove production quality, but they make the implementation inspectable.

Open code matters here because relay policy is the product. NWCLay's value is not a brand promise that says `NWC only`. Its value is the code path that rejects wrong kinds, rejects weak filters, stores briefly and cleans the database. Those behaviors can be audited in the repository.

How it fits Nostr Wallet Connect

Nostr Wallet Connect, specified in NIP-47, connects client apps to Lightning wallet services through Nostr relays. The wallet service publishes information, receives encrypted requests and sends encrypted responses. The client app does not take custody of the wallet, but it can ask the wallet service to perform approved actions.

The NWC docs describe the relay as the place where the wallet service is connected and listening for events. A connection secret includes a `relay` parameter, and the app uses that relay URL to reach the wallet service. The relay is therefore part of the payment path even though it is not the wallet.

NWCLay focuses on that relay role. It is built to carry the event kinds used by NWC rather than acting as a general public database. This is similar in spirit to Alby's recommendation that NWC traffic should use a dedicated relay when reliability and metadata boundaries matter.

The practical mental model is simple. The app holds a connection secret. The wallet service listens on the relay. The relay accepts or rejects Nostr events according to its policy. The Lightning backend sits behind the wallet service. If any layer is misunderstood, debugging becomes painful.

The event kinds are the whole point

The NWCLay README says the relay only accepts kinds from the NWC specification. The current `main.go` code makes that concrete. It accepts event kinds 13194, 23194, 23195 and 23196 and rejects anything else.

Those numbers are not decorative. In NWC, kind 13194 is the wallet-service info event, kind 23194 is the request, kind 23195 is the response, and notification behavior has changed over time. The current NWC docs list kind 23197 for notifications and kind 23196 as the legacy NIP-04 notification kind.

That means NWCLay has a practical compatibility question. The inspected code accepts 23196, but not 23197. The live relay reports NIP-47 support, but an app or wallet service that uses the newer notification kind should test behavior directly instead of assuming every NIP-47 detail is accepted.

This is exactly why a specialized relay deserves a real article. A broad category label like `NWC relay` is not enough. The accepted kind list decides whether your wallet service can publish the specific events it needs. Before production use, send tiny harmless tests for every kind your integration requires.

Filter rules protect the relay

NWCLay also restricts subscriptions. The code rejects filters without kinds. It then requires at least one targeting field: an authors list, a `#p` tag or a `#e` tag. That means a client cannot ask the relay vague questions and expect it to behave like a discovery index.

This is the right instinct for NWC traffic. Wallet requests and responses should be scoped around known parties and known events. A wallet service should not need to subscribe to the whole relay. A client app should not need to scan broad history. Precise filters reduce load and reduce accidental exposure.

The relay also rejects count filters. That matters because count queries are useful on some social relays, but they do not belong in the narrow NWC delivery path NWCLay is trying to maintain. If your client expects relay-count behavior for diagnostics, it should not rely on NWCLay for that.

For builders, the test is straightforward. Subscribe with the exact kinds you need. Include the wallet service author, the app author, the `p` tag or the event reference needed for your flow. Watch for rejects and handle them as first-class errors, not as silent connection failures.

Short retention is a design choice

NWCLay uses a database, but that does not mean it wants to become a long-term archive. The README says it keeps events for a while for reliability. The `.env.example` file shows `KEEP_IN_MINUTES=10` and `ACCEPT_WINDOW_IN_MINUTES=1` as example values.

The code makes the behavior more concrete. New events outside the allowed time window are rejected. A background cleanup job runs on a ticker and deletes most stored events after the configured retention window. The job keeps kind 13194 differently from the other NWC traffic, which makes sense because wallet-service info is more durable than individual payment requests.

That short retention supports delivery without turning the relay into a permanent payment-message archive. It also means late clients and sleepy wallet services have a hard deadline. If the wallet service is offline too long, the relay may no longer have the event the client hoped it would deliver.

This is not a bug by itself. It is a tradeoff. NWCLay favors fresh, focused NWC traffic. If your product expects long-lived queueing, delayed approvals or forensic history on the relay, you need to design around that instead of discovering it during a failed checkout.

Docker is the deployment path

The NWCLay README gives a Docker-first installation path. It points to the `dezhtech/nwclay` Docker image and shows a `docker run` example with a published port, a data volume and environment variables for relay name, pubkey, description, URL, icon, banner, contact, port, working directory and retention values.

The repository also includes a `compose.yml` file and an `.env.example`. Those are worth opening before you deploy because they show the expected shape of the service: container name, image, port mapping, data volume and the operator metadata exposed through the relay information document.

For a small operator, this is approachable. You can run a specialized NWC relay without writing a relay from scratch. For a serious wallet service, approachable does not mean finished. You still need a reverse proxy, TLS, monitoring, logs, volume backups, firewall rules and a plan for image updates.

The relay itself does not create wallet policies. A hosted NWCLay instance should be treated like payment-adjacent infrastructure. Keep it small, observable and easy to replace. If the relay becomes important to users, pin image versions and document the exact deployment configuration.

The environment variables tell you what matters

NWCLay's configuration file defines the operator-facing knobs. The relay name, pubkey, description, URL, contact, icon and banner populate the public relay identity. The working directory and port control the local service. The retention and accept-window settings control event freshness.

Those values are not just cosmetics. A wrong relay URL can break NWC connection strings. A missing contact makes incident handling harder. A misleading description can cause people to send the wrong traffic. A retention window that is too short can produce intermittent failures. A window that is too loose can store more than intended.

The default examples are useful for a local start, but they should not become accidental production policy. If you run a public NWCLay instance, decide how fresh events must be, how long you keep them, what host name users should trust and how they should contact you if wallet-service delivery fails.

A good relay information document is part of trust. It does not prove good operation, but it tells clients and humans where they are. Since NWC connection strings include the relay, the public identity of that relay should be boringly precise.

NIP-11 gives the reader a live checklist

NIP-11 defines the relay information document. For NWCLay, it is not optional background reading. It is the quickest way to learn what a specific deployment claims about name, description, contact, software, version and supported NIPs.

A reader can test the live relay by requesting `https://nwclay.paywithflash.com/` with `Accept: application/nostr+json`. The response checked for this article included supported NIPs 1, 47 and 9. The visible web page showed a simpler supported-NIP display. That difference is a reminder to inspect the machine-readable response directly.

NIP-11 is also where operator metadata becomes visible. If someone clones NWCLay and runs a different endpoint, the code name alone is not enough. Check the host, contact, software URL and version. Do not assume that every NWCLay deployment has the same operator, retention window or update state.

For app builders, put this in the preflight checklist. Fetch NIP-11. Record the version. Confirm NIP-47 is advertised. Confirm the URL in the connection string matches the relay you tested. Then perform a small end-to-end NWC request before you put user money behind the flow.

Why NIP-09 appears

The live NWCLay NIP-11 response advertises NIP-09 in addition to NIP-01 and NIP-47. NIP-09 covers event deletion requests. In the NWCLay code, relay behavior includes delete and replace hooks wired to the event store backend.

Do not overread that signal. NIP-09 support does not mean NWCLay is an archival social relay or a general moderation system. It means the relay advertises support for deletion-request semantics while still applying its NWC-focused acceptance policy.

For a payment-adjacent relay, deletion semantics can matter because clients may want stale or mistaken events removed where the relay supports it. But NIP-09 has limits. Relays may delete events according to policy, and deletion requests are not a universal eraser across the network.

The practical advice is narrow. If your integration relies on deletion or replacement behavior, test it against the exact relay instance. If it does not, do not treat the NIP-09 line as a reason to send unrelated event kinds to NWCLay.

The code stack is familiar Nostr plumbing

NWCLay uses known Go-based Nostr components. The parent DDSR README names Khatru, Event Store, Blob Store and Go Nostr as building blocks. The NWCLay code imports Nostr relay and event-store packages rather than inventing every protocol piece from scratch.

Khatru is a framework for building custom Nostr relays. Eventstore provides storage adapters for Nostr events. Go Nostr is a widely used Go library for Nostr protocol work. Badger appears in the NWCLay storage path as the database backend used by the event store.

Those dependencies make the project easier to inspect because a reader can separate standard relay mechanics from NWCLay's policy choices. The interesting parts are not websocket handling in the abstract. The interesting parts are the reject functions, allowed kinds, filter requirements and cleanup job.

That does not eliminate dependency risk. Operators should watch upstream releases, pinned versions, Docker tags and storage compatibility. A specialized relay is still a software service with supply-chain, runtime and data-path responsibilities.

What PayWithFlash contributes here

The live relay contact points to PayWithFlash. PayWithFlash describes itself as a treasury platform for Bitcoin businesses, with tooling around wallets, exchanges, fiat rails, accountants, cost basis, transaction labels, payment routing and exports.

That does not make PayWithFlash the protocol, and it does not change NWCLay's open-source code path. It does tell a reader who is associated with the live endpoint checked here. When a relay transports NWC payment traffic, knowing the operator contact is part of evaluating the service.

The contact path matters most when something breaks. If an app cannot reach a wallet service, the wallet service operator may need to know whether the relay changed versions, started rejecting filters, hit rate limits, lost storage or went offline.

Use the contact signal sensibly. It is not a guarantee of uptime or custody. It is a place to begin incident communication for the live deployment. For your own deployment, set contact metadata that actually reaches the person responsible for the relay.

A real SDK example uses the relay

NWCLay is not only a README entry. The Dart `nip47` package example on pub.dev uses `wss://nwclay.paywithflash.com` as the relay URL in example code. That is a useful signal because it shows the relay being used as a concrete NWC test endpoint in developer material.

An example URL is not a production endorsement. SDK examples often choose a working public endpoint so developers can understand the flow. The right lesson is that NWCLay is visible enough in the NWC developer ecosystem to appear in code examples, and that developers may copy the endpoint into tests.

That makes clarity even more important. If developers paste the endpoint into production without checking event kinds, retention and operator expectations, the example becomes accidental infrastructure. Examples are for learning. Production should have explicit relay decisions.

If you are building an SDK or tutorial, label the relay role carefully. Say that the relay carries NWC events. Say that the wallet service and app still need their own keys, permissions and supported methods. Avoid wording that makes the relay sound like the wallet.

Metadata does not disappear

NWC encrypts request and response payloads, and the current specification has moved toward NIP-44 while preserving older NIP-04 compatibility in parts of the ecosystem. Encryption protects the contents of payment requests from the relay, assuming implementations are correct.

The relay still sees metadata. It sees event kinds, timing, tags, pubkeys, subscriptions, connection patterns and retry behavior. A specialized relay like NWCLay may reduce unrelated social noise and focus the policy surface, but it does not make communication invisible.

This matters for wallet services because payment behavior is sensitive even when amounts and invoices are encrypted. A relay that sees frequent request traffic between specific keys can infer activity. A relay that sees errors or retries can infer integration trouble. Those are normal transport realities, not unique NWCLay flaws.

The best defense is connection hygiene. Use per-app keys where the wallet supports it. Keep app permissions narrow. Avoid using a main identity key as a payment-control key. Rotate and revoke old connections. Do not publish broad filters. Keep the relay list intentional.

Failure modes to test

A happy-path NWC payment test is not enough. Test what happens when the client sends an unsupported kind, a filter without authors or tags, a stale event, a count filter or a request after the wallet service has been offline longer than the retention window.

Then test wallet-service behavior. Restart the wallet service while the app is waiting. Send a request just before a connection budget expires. Send a duplicate request after a timeout. Watch whether the wallet service deduplicates, rejects, pays twice, returns a clear error or leaves the user guessing.

Also test the relay URL itself. Some apps handle websocket errors clearly; others hide them behind generic `payment failed` messages. If NWCLay rejects a filter, the user should not be left thinking their wallet is empty or their invoice is invalid.

For production, create a small synthetic monitor. Fetch NIP-11, open a websocket, publish a harmless info or test event if appropriate for your environment, confirm the expected reject behavior for wrong traffic and alert when the relay stops behaving like the version you documented.

How it compares with Alby NWC Relay

Alby NWC Relay and NWCLay sit in the same conceptual shelf, but they are not the same product. Alby's relay is operated infrastructure documented for wallet-service builders and partners. NWCLay is an open-source domain-specific relay implementation with a public PayWithFlash-hosted instance.

Alby's documentation emphasizes public access, rate limits, partner relay services, HTTP API options, RabbitMQ and Kubernetes-backed scaling, and persisted ephemeral delivery. NWCLay's public code emphasizes strict kind acceptance, filter checks, short retention and a small Docker deployment model.

That difference is useful. If you are building a wallet service and want operated infrastructure with a documented partner path, Alby's relay may be the first comparison. If you want to inspect or run a focused NWC-only relay yourself, NWCLay is more directly relevant.

The right choice depends on the failure mode you can handle. A hosted relay gives you someone else's operation. A self-run NWCLay gives you control and responsibility. In both cases, the app and wallet service still need careful permissions, logging and user-facing error handling.

Where NWCLay is useful

NWCLay is useful when you need a relay that is intentionally boring for NWC traffic. It can be a test endpoint for developers, a focused relay for a small wallet-service deployment or a reference implementation for people learning how to narrow relay policy around a protocol use case.

It is also useful as a teaching example. The code shows how a relay can restrict event kinds, reject weak filters and clean old data. That is a practical lesson for anyone who thinks a Nostr relay must always be a broad public note store.

It is less useful if you need social discovery, search, long-term archival storage, arbitrary event kinds, relay count queries or a marketplace of unrelated Nostr traffic. Those are different relay jobs. NWCLay is strongest when the relay URL appears inside an NWC connection string and nothing else.

The safest first deployment is small. Run it, fetch NIP-11, connect one wallet service, connect one client, send tiny test payments, inspect rejects and logs, then decide whether it belongs in your real wallet path.

What to verify before you rely on it

Start with the live endpoint. Fetch the NIP-11 document, record the software URL, supported NIPs and version, and compare them with the repository. Do not assume the running deployment matches the latest code.

Next verify event compatibility. Confirm whether your wallet service emits kind 13194, 23194, 23195, 23196 or 23197. If it depends on kind 23197 notifications, test carefully because the inspected NWCLay code accepts 23196 but not 23197.

Then verify filter compatibility. Make sure subscriptions include kinds and at least the author, `#p` tag or `#e` tag that NWCLay expects. Confirm your client handles count-filter rejection and other relay notices gracefully.

Finally verify operation. Check Docker image tag, volume location, retention minutes, accept window, system time sync, reverse proxy, TLS, logs, disk usage, restart behavior and contact metadata. A relay carrying payment-capability messages deserves a real runbook even when the code is small.

The bottom line

NWCLay is a focused Nostr Wallet Connect relay, not a wallet and not a general social relay. Its value is in saying no: no broad event kinds, no vague filters, no count filters and no long-lived storage for traffic that should be fresh.

That makes it a useful piece of the NWC ecosystem. A wallet service and app need a relay path. NWCLay gives that path a narrow policy surface that can be inspected and self-hosted. The public PayWithFlash endpoint makes it easy to test; the GitHub code makes it possible to understand.

The limits are just as important as the strengths. Check the live version. Check accepted event kinds. Check notification behavior. Check retention. Check the exact relay URL in the connection string. Check that your app can explain relay failures to the user.

Use NWCLay when you want NWC relay infrastructure that behaves like NWC infrastructure. Do not use it as a generic relay, do not treat it as the wallet, and do not let a clean relay hide sloppy app permissions. In NWC, the relay is only one layer, but it is a layer users will feel the moment payment delivery breaks.

Sources worth opening

Open the live relay information document, then read the NWCLay README and the code files that enforce event kinds, filter rules and retention. After that, compare NIP-47 and the NWC docs so the relay is not confused with the wallet service it carries.

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

How to use this page

Keep the relay layer visible.

Search relay tools, relay policy, monitoring and infrastructure pages when availability or moderation choices matter.

RelaysMore relay infrastructureRelay pages and policy notesRelays, monitoring, policy and infrastructure.Browse pages
Relays contribution visual cue 1
Relays contribution visual cue 2
Relays contribution visual cue 3
Relays contribution visual cue 4
Relays 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.