LaWallet NWC
Guides

Client SDK & React Hooks

TypeScript SDK and React Hooks for interacting with the LaWallet NWC API.

Overview

Two packages provide typed access to the LaWallet NWC backend:

  • Client SDK — standalone TypeScript client for all API endpoints
  • React Hooks — React hooks built on top of the SDK with caching and state management

TypeScript Client SDK

Package

  • Published as standalone npm package
  • Auto-generated TypeScript types from API schemas
  • Unit tests with MSW mocks

API Coverage

  • Lightning Address: create, lookup, update, delete
  • Alias/Redirect: set target, remove, get status
  • NWC Connection: connect, disconnect, status
  • Authentication: JWT login, Nostr login, refresh, revoke
  • Webhooks: subscribe, unsubscribe, list
  • Wallet: balance, send, receive

Delivered

  • Month 2: Core SDK (auth, addresses, redirect, NWC, webhooks)
  • Month 3: Courtesy NWC methods
  • Month 5: LUD-21/22, redirect, zap methods
  • Month 6: Full documentation + API reference

React Hooks Package

Package

  • Published as @lawallet-nwc/react
  • Built on top of Client SDK
  • SWR or React Query for caching + revalidation
  • Loading, error, and success states on every hook
  • TypeScript generics for type-safe responses

Hooks Reference

HookPurposeMonth
useAddressCRUD single lightning address (including redirect config)2
useAddressesList/search/filter with pagination2
useNWCConnectionConnect, disconnect, status polling2
usePaymentsPayment history, real-time updates2
useAuthJWT + Nostr login, session state, logout2
useWebhooksSubscribe, unsubscribe, list active hooks2
useWalletBalance, send, receive, NWC status2
useCourtesyNWCProvision/revoke courtesy NWC from proxy3
useZapSend/receive zaps, verify receipts5
useVerifyPayment settlement status (LUD-21)5
useRedirectAddress alias/redirect configuration5

Interactive Example: useAddress Hook

Try editing the code below to see how the useAddress hook works:

import { useState } from "react";

// Simulated useAddress hook (demonstrates the API pattern)
function useAddress(username: string) {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<any>(null);

const lookup = async () => {
  setLoading(true);
  // Simulates API call to GET /api/addresses/:username
  await new Promise(r => setTimeout(r, 800));
  setData({
    username,
    lightningAddress: username + "@yourdomain.com",
    nwcStatus: "connected",
    createdAt: new Date().toISOString(),
  });
  setLoading(false);
};

return { data, loading, lookup };
}

export default function App() {
const [username, setUsername] = useState("alice");
const { data, loading, lookup } = useAddress(username);

return (
  <div style={{ fontFamily: "system-ui", padding: 20 }}>
    <h2>⚡ useAddress Hook Demo</h2>
    <div style={{ marginBottom: 16 }}>
      <input
        value={username}
        onChange={e => setUsername(e.target.value)}
        placeholder="Enter username..."
        style={{ padding: "8px 12px", borderRadius: 6, border: "1px solid #ccc", marginRight: 8 }}
      />
      <button
        onClick={lookup}
        disabled={loading}
        style={{
          padding: "8px 16px",
          borderRadius: 6,
          background: "#7c3aed",
          color: "white",
          border: "none",
          cursor: loading ? "wait" : "pointer",
        }}
      >
        {loading ? "Looking up..." : "Lookup Address"}
      </button>
    </div>
    {data && (
      <pre style={{
        background: "#1e1e2e",
        color: "#a6e3a1",
        padding: 16,
        borderRadius: 8,
        fontSize: 13,
      }}>
{JSON.stringify(data, null, 2)}
      </pre>
    )}
  </div>
);
}

Interactive Example: useAuth Hook

import { useState } from "react";

type AuthState = {
isAuthenticated: boolean;
pubkey: string | null;
role: string | null;
token: string | null;
};

// Simulated useAuth hook
function useAuth() {
const [state, setState] = useState<AuthState>({
  isAuthenticated: false,
  pubkey: null,
  role: null,
  token: null,
});
const [loading, setLoading] = useState(false);

const login = async (pubkey: string) => {
  setLoading(true);
  // Simulates NIP-98 -> JWT flow
  await new Promise(r => setTimeout(r, 1000));
  setState({
    isAuthenticated: true,
    pubkey,
    role: "user",
    token: "eyJhbGciOiJIUzI1NiIs...",
  });
  setLoading(false);
};

const logout = () => {
  setState({ isAuthenticated: false, pubkey: null, role: null, token: null });
};

return { ...state, loading, login, logout };
}

export default function App() {
const auth = useAuth();

return (
  <div style={{ fontFamily: "system-ui", padding: 20 }}>
    <h2>🔐 useAuth Hook Demo</h2>
    <div style={{
      padding: 16,
      borderRadius: 8,
      background: auth.isAuthenticated ? "#dcfce7" : "#fef3c7",
      marginBottom: 16,
    }}>
      <strong>Status:</strong>{" "}
      {auth.isAuthenticated ? "✅ Authenticated" : "⚠️ Not authenticated"}
    </div>

    {!auth.isAuthenticated ? (
      <button
        onClick={() => auth.login("npub1abc...xyz")}
        disabled={auth.loading}
        style={{
          padding: "10px 20px",
          borderRadius: 8,
          background: "#f97316",
          color: "white",
          border: "none",
          cursor: auth.loading ? "wait" : "pointer",
          fontSize: 14,
        }}
      >
        {auth.loading ? "Signing in with Nostr..." : "Login with Nostr (NIP-98)"}
      </button>
    ) : (
      <div>
        <pre style={{
          background: "#1e1e2e",
          color: "#89b4fa",
          padding: 16,
          borderRadius: 8,
          fontSize: 13,
        }}>
{JSON.stringify({
pubkey: auth.pubkey,
role: auth.role,
token: auth.token?.slice(0, 20) + "...",
}, null, 2)}
        </pre>
        <button
          onClick={auth.logout}
          style={{
            padding: "8px 16px",
            borderRadius: 6,
            background: "#ef4444",
            color: "white",
            border: "none",
            cursor: "pointer",
            marginTop: 8,
          }}
        >
          Logout
        </button>
      </div>
    )}
  </div>
);
}

Lifecycle

MonthSDK MilestoneHooks Milestone
2Core: auth, addresses, redirect, NWC, webhooks. npm publish.7 base hooks. Published as @lawallet-nwc/react.
3Frontend + Courtesy NWC Proxy consume SDK.Add useCourtesyNWC.
5Add LUD-21/22, redirect, zap methods.Add useZap, useVerify, useRedirect. Update useWebhooks.
6Full docs + API reference.Full docs + usage examples.

On this page