create-fedi-app
APIs

Nostr (NIP-07)

Nostr identity in Fedi mini apps — getPublicKey, signEvent, getRelays, nip04 encryption, and React hooks.

Fedi injects window.nostr implementing NIP-07 — browser-based Nostr signing without exposing private keys to your app.

Provider lifecycle

// lib/nostr/provider.tsx — simplified
useEffect(() => {
  if (window.nostr) {
    const pk = await window.nostr.getPublicKey();
    setProvider(window.nostr);
    setPubkey(pk);
  } else if (mockProvider && process.env.NODE_ENV === 'development') {
    const pk = await mockProvider.getPublicKey();
    setProvider(mockProvider);
    setPubkey(pk);
  }
}, []);

Unlike WebLN, NIP-07 does not require an explicit enable() call. getPublicKey() is the permission gate — Fedi prompts the user on first access.

NostrProvider interface

interface NostrProvider {
  getPublicKey(): Promise<string>;
  signEvent(event: UnsignedNostrEvent): Promise<NostrEvent>;
  getRelays(): Promise<Record<string, { read: boolean; write: boolean }>>;
  nip04: Nip04;
}

getPublicKey()

Returns the user's hex-encoded secp256k1 public key (64 chars, no 0x prefix).

| Returns | Promise<string> — hex pubkey | | Errors | User denial |

const pubkey = await window.nostr!.getPublicKey();
// "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"

signEvent(event)

Signs a Nostr event. The provider fills in id, pubkey, and sig.

interface UnsignedNostrEvent {
  created_at: number;
  kind: number;
  tags: string[][];
  content: string;
}

interface NostrEvent extends UnsignedNostrEvent {
  id: string;
  pubkey: string;
  sig: string;
}
ParameterTypeDescription
event.created_atnumberUnix timestamp
event.kindnumberEvent kind (1 = text note, 9734 = zap request, etc.)
event.tagsstring[][]Nostr tags
event.contentstringEvent body

| Returns | Signed NostrEvent | | Errors | User denial, invalid event structure |

const signed = await window.nostr!.signEvent({
  kind: 1,
  created_at: Math.floor(Date.now() / 1000),
  tags: [],
  content: 'Hello from a Fedi mini app',
});
// Publish signed to relays via nostr-tools or WebSocket

getRelays()

Returns the user's configured relay permissions.

// { "wss://relay.damus.io": { read: true, write: true }, ... }
const relays = await window.nostr!.getRelays();

nip04

NIP-04 encrypted direct messages.

interface Nip04 {
  encrypt(pubkey: string, plaintext: string): Promise<string>;
  decrypt(pubkey: string, ciphertext: string): Promise<string>;
}

React hooks

useNostr()

function useNostr(): {
  provider: NostrProvider | null;
  pubkey: string | null;
  npub: string | null;       // bech32-encoded pubkey
  isLoading: boolean;
  error: Error | null;
  isConnected: boolean;
}

npub is derived from hex pubkey via bech32 encoding.

useIdentity()

Convenience wrapper for common identity operations.

function useIdentity(): {
  pubkey: string | null;
  npub: string | null;
  displayNpub: string | null;  // truncated "npub1abc...xyz"
  getPublicKey: () => Promise<string | null>;
  signEvent: (event: UnsignedNostrEvent) => Promise<NostrEvent | null>;
  isConnecting: boolean;
}
const { displayNpub, signEvent } = useIdentity();

if (!displayNpub) return <button onClick={getPublicKey}>Connect Nostr</button>;

Mock provider

MockNostrProvider uses a well-known test keypair (documented in source — never use in production):

// Deterministic test pubkey from privkey = 0x00...01
const provider = new MockNostrProvider();

Set a custom mock npub via the Fedi Dev Toolbar input field.

Event kinds used in modules

KindNameUsed by
1Text notenostr-feed
9734Zap requestnostr-feed (ZapButton)
9735Zap receiptnostr-feed

Common errors

ErrorCauseFix
Failed to connect NostrUser denied getPublicKeyShow connect button, explain identity use
useNostr must be used within a NostrProviderMissing providerWrap in <NostrProvider>
Relay publish failsWrite-disabled relayCheck getRelays() write permissions

Spec reference

On this page