off1… address is derived from that public key:
Read an address
localAddress() returns the local address after identity initialization or null if initialization is unavailable. Handle startup diagnostics and check the result. deriveAddress(publicKey) can be called on an instance before start() and rejects a key that is not 32 bytes.
Register identity_ready before startup and narrow event.type before reading address. For recipients, use peer_id from neighbor_discovered or sender from a received message. A username, profile string and portal Application ID are not routing addresses.
Preserve the namespace
The storage namespace derives from(appId, profile). Keep both stable across restarts. A separate account should use a separate profile and an explicit logout/reset policy.
profile selects stored state, but it is not private metadata: iOS, Android and Python send it to the internet relay in X-Device-ID. Use an opaque identifier and put no personal data in it. The relay also sees routing metadata.
On iOS, Keychain identity material can survive uninstall. Reinstalling is not an identity reset. Use the SDK’s deliberate wipePersistedState flow when deleting an account’s local identity and state; also delete application-owned records and custom stores according to your logout policy.
First contact
UsecreateInvite to create an invite, transfer it by QR or another trusted channel, then parseInvite to validate and extract its address/key information. Confirm the intended person or device through your application’s enrollment process before granting permissions.
resolveUsername is an opt-in discovery mechanism. It requires Nostr usernameDiscoveryEnabled and coldContactEnabled. It returns true if this call started the lookup and false if one was already running; exactly one username_resolved follows either way. Rejected calls do not promise a result event. Register that listener before issuing the query. Several devices can claim a name, so never automatically select a result as the trusted account holder.
For an existing account directory, bind the device key to the account by verifying a signature over a fresh server-issued nonce, checking the derived address, then storing the verified binding. Discovery alone is not account authentication.
Migrating from userId
v0.21.0 replaceduserId with profile. Keeping the same value retains your own storage namespace, but outbound recipients must now be verified off1… addresses. Preserve application records; resolve old peer identifiers through verified enrollment rather than renaming every stored key.
See upgrade guidance and the released threat model.
