Verification Model
When a client application (like a wallet or a social client) parses a Proxy Request (Kind 5523) or its resultant Zap Receipt (Kind 5521), it needs to resolve the legacy identifier into a native Nostr identity to display a "Verified" rich profile.
This protocol implements a deterministic, network-based verification model to balance speed and security.
The Identity Lookup
The verification flow relies on querying the Nostr network for an Identity Connection (Kind 35521) that binds the target identifier hash to a Nostr Public Key.
How it works:
- The client extracts the 3-element identity tag (e.g.,
["p", "<ConnectionKey>", "discord"]). - It constructs a filter query targeting the Nostr network (and specifically the ZSP's relays):
{
"kinds": [35521],
"#d": ["<ConnectionKey>"]
}
- The client receives the 35521 event.
- (Optional but Recommended) The client fetches the Kind 35522 from the relay URL in the
etag to confirm a trusted Identity Authority (IA) attested to this linkage. If the relay returns the event and it is not expired, the connection is considered Verified.
Verification States
Clients should map the outcome of this query to clear UI indicators:
| State | Outcome | Recommended UI |
|---|---|---|
| Verified | Valid 35521 event found, mapping the hash to a Nostr Key. | ✅ Native Nostr Profile |
| Pending (Fallback) | No 35521 event found. | ⏳ Fallback LIDP Profile (e.g., Discord Avatar fetched from the ZSP API) |
| Spoofed | 35521 found, but the Kind 35522 fetched from the e tag relay is invalid, missing, or revoked. | ⚠️ Red Warning ("Unverified / Suspicious") |
By following this model, clients ensure that users are only shown verified identities when cryptographic proof has been surfaced, falling back gracefully to custodial profiles when the user hasn't completed their Claim Flow.