{"id":"7ecd70f3f0677caacd1d48af3b762e9e2d8c29cd928734f3941d99bfd0cf007e","pubkey":"da19f1cd34beca44be74da4b306d9d1dd86b6343cef94ce22c49c6f59816e5bd","created_at":1774618246,"kind":30817,"tags":[["title","NIP-TRUST: Portable Trust Networks"],["k","30515"],["k","30517"],["d","nip-trust"]],"content":"NIP-TRUST\n==========\n\nPortable Trust Networks\n------------------------\n\n`draft` `optional`\n\nTwo addressable event kinds for trust revocation and provider endorsements on Nostr. List-based trust data (trusted providers, recommendations, collectives, block lists) is handled by NIP-51.\n\n> **Standalone.** This NIP works independently on any Nostr application.\n\n## Motivation\n\nTrust relationships form organically through repeated interactions, yet no Nostr protocol standardises how these relationships are expressed, shared, or discovered across applications. NIP-02 contact lists are binary (follow/don't follow) with no category scoping, ratings, or reasons. NIP-51 lists provide flexible, categorised grouping of pubkeys, but two critical trust primitives cannot be modelled as list membership:\n\n1. **Trust revocation** must be a publicly timestamped, reason-coded event. Removing someone from a list is silent and leaves no audit trail. Revocations need tiered visibility, notification rules, and a permanent record that platform operators and safety contacts can query.\n2. **Provider endorsements** are directional attestations from one provider to another. They carry endorsement types, weighting criteria, and withdrawal semantics. A list entry cannot express \"I vouch for this person's skill, weighted by my own track record.\"\n\nThis NIP defines these two primitives. For list-based trust data, see [Composing with NIP-51](#composing-with-nip-51) below.\n\nTogether, NIP-TRUST and NIP-51 enable:\n\n- **Personal trust is portable** - follows the user's Nostr keypair across clients\n- **Word-of-mouth discovery** - shareable recommendation lists via NIP-51 with deep links or NIP-44 encryption\n- **Cold-start solved** - provider-to-provider endorsements create trust bridges for new providers\n- **Provider collectives** - groups of providers coordinate under a shared NIP-51 list identity\n- **Social graph discovery** - existing data (NIP-02 contact lists, NIP-51 trust lists, `kind:30517` endorsements) surfaces trust signals with no new infrastructure\n\n## Relationship to Existing NIPs\n\n### NIP-02 (Contact Lists)\n\nNIP-02 provides binary follow/unfollow. Trust revocations and endorsements add structured, reasoned trust signals that go beyond \"I follow this person.\" A user may follow thousands of accounts but only endorse a handful of providers for specific skills.\n\n### NIP-51 (Lists)\n\nNIP-51 handles all list-based trust data that was previously modelled as dedicated kinds. Specifically:\n\n- **Trusted Provider Lists** use `kind:30000` with `p` tags carrying category, rating, and reason metadata.\n- **Shareable Recommendations** use `kind:30000` with `visibility` tags and optional NIP-44 encryption for private recommendations.\n- **Provider Collectives** use `kind:30000` with collective metadata tags. Members are `p` tags with role positions.\n- **Block Lists** use `kind:10000` (mute list) with category-scoped entries.\n\nNIP-TRUST provides the two event types NIP-51 cannot model: revocations (which must be publicly timestamped, not just list removal) and endorsements (which are directional attestations between providers, not list membership). See [Composing with NIP-51](#composing-with-nip-51) for concrete JSON examples.\n\n### NIP-56 (Reporting)\n\nNIP-56 flags content for relay-level moderation. Trust revocation signals relationship termination between known parties; different semantics entirely. A revocation says \"I no longer trust this entity\" while a report says \"this content violates relay policy.\"\n\n### Community NIPs\n\n- **TSM Trust Service Machines (kinds 37570–37572):** The TSM framework defines a request/response pattern for trust computation services: service announcements (37570), output standards (37571), and service requests (37572). TSM provides infrastructure for computing and querying trust metrics algorithmically. NIP-TRUST provides the primitive events that TSM could consume — trust revocations are first-party signed records (\"I no longer trust this entity and here is why\"), and provider endorsements are directional attestations (\"I endorse this provider for plumbing\"). These human-authored trust signals are the raw data that a TSM provider would ingest to compute aggregate trust scores. TSM computes; NIP-TRUST records.\n\n## Kinds\n\n| kind  | description          |\n| ----- | -------------------- |\n| 30515 | Trust Revocation     |\n| 30517 | Provider Endorsement |\n\n---\n\n## Kind 30515: Trust Revocation\n\nExplicit trust removal with reason-tiered visibility. Provides an audit trail and notification. Addressable; each revocation uses a unique `d` value.\n\n```json\n{\n    \"kind\": 30515,\n    \"created_at\": 1708300800,\n    \"tags\": [\n        [\"d\", \"<revoker-pubkey>:<revoked-pubkey>:plumbing:1708300800\"],\n        [\"p\", \"<revoked-pubkey>\"],\n        [\"alt\", \"Trust revocation: quality decline in plumbing\"],\n        [\"domain\", \"plumbing\"],\n        [\"t\", \"domain:plumbing\"],\n        [\"reason_code\", \"quality_decline\"],\n        [\"e\", \"<nip-51-trust-list-event-id>\"]\n    ],\n    \"content\": \"<NIP-44 encrypted to platform operator(s): 'Quality dropped significantly over last 3 jobs.'>\",\n    \"id\": \"<32-byte-hex>\",\n    \"sig\": \"<64-byte-hex>\"\n}\n```\n\n### Tags\n\nRequired tags:\n\n* `d` (MUST): Unique revocation identifier. Recommended format: `<revoker-pubkey>:<revoked-pubkey>:<category>:<timestamp>`.\n* `p` (MUST): Revoked party's hex pubkey.\n* `domain` (MUST): Category context. This is a multi-letter tag; relays cannot filter on it. Clients MUST post-filter by `domain` after retrieval.\n* `reason_code` (MUST): One of the defined codes.\n\nOptional tags:\n\n* `t` (RECOMMENDED): `[\"t\", \"domain:<category>\"]` (e.g. `[\"t\", \"domain:plumbing\"]`). Enables relay-side discovery by domain via `#t` filters. The `domain` tag remains the canonical source; the `t` tag is a relay-filterable mirror.\n* `e` (OPTIONAL): Reference to the NIP-51 trust list event the revocation applies to.\n\n### Reason Codes\n\n| Code | Visibility | Notification |\n| ---- | ---------- | ------------ |\n| `safety_concern` | Platform operators + safety contacts | NIP-17 to revoked party (code only, NOT free-text) |\n| `no_show` | Platform operators | NIP-17 to revoked party (code only) |\n| `quality_decline` | Platform operators | NIP-17 to revoked party (code only) |\n| `personal_preference` | Revoked party only | NIP-17 with reason code |\n| `moved_area` | Revoked party only | NIP-17 with reason code |\n| `inactive` | Silent | No notification |\n\nContent encryption: For safety/quality codes, content MUST be NIP-44 encrypted to relevant platform operators. The revoked party receives only the reason code via NIP-17, never the free-text. This prevents retaliation while giving signal.\n\n### Revocation Lifecycle\n\nWhen a trust revocation is published, the revoking party SHOULD also remove the corresponding `p` entry from their NIP-51 trusted provider list. The revocation event serves as the auditable record; the list update reflects the current state.\n\nClients querying trust status SHOULD check both the NIP-51 list (current membership) and `kind:30515` events (historical revocations). A provider absent from a trust list may have been silently removed or may have been formally revoked. Only a `kind:30515` event confirms formal revocation with a reason.\n\n### REQ Filters\n\n```json\n[\n    {\"kinds\": [30515], \"authors\": [\"<revoker-pubkey>\"]},\n    {\"kinds\": [30515], \"#p\": [\"<revoked-pubkey>\"]},\n    {\"kinds\": [30515], \"authors\": [\"<revoker-pubkey>\"], \"#p\": [\"<revoked-pubkey>\"]}\n]\n```\n\n---\n\n## Kind 30517: Provider Endorsement\n\nProvider-to-provider vouching. Experienced providers endorse newer providers, solving the cold-start problem. Addressable; each endorser can publish at most one endorsement per endorsed provider per category.\n\n```json\n{\n    \"kind\": 30517,\n    \"tags\": [\n        [\"d\", \"<endorser-pubkey>:<endorsed-pubkey>:plumbing\"],\n        [\"p\", \"<endorsed-pubkey>\"],\n        [\"alt\", \"Provider endorsement: skill in plumbing\"],\n        [\"domain\", \"plumbing\"],\n        [\"t\", \"domain:plumbing\"],\n        [\"endorsement_type\", \"skill\"],\n        [\"e\", \"<endorser-profile-event-id>\"]\n    ],\n    \"content\": \"Worked alongside Mo for 3 years. Solid work, reliable, always on time.\",\n    \"id\": \"<32-byte-hex>\",\n    \"sig\": \"<64-byte-hex>\"\n}\n```\n\n### Endorsement Types\n\n| Type | Meaning |\n| ---- | ------- |\n| `skill` | \"They're good at the job\" - competence |\n| `reliability` | \"They show up and follow through\" - dependable |\n| `safety` | \"I'd trust them in my home\" - trustworthy in sensitive contexts |\n| `general` | Broad endorsement, no specific category |\n\n### Tags\n\nRequired tags:\n\n* `d` (MUST): Unique identifier. Recommended format: `<endorser-pubkey>:<endorsed-pubkey>:<category>`.\n* `p` (MUST): Endorsed provider's hex pubkey.\n* `domain` (MUST): Category context. This is a multi-letter tag; relays cannot filter on it. Clients MUST post-filter by `domain` after retrieval.\n* `endorsement_type` (MUST): One of the defined types.\n\nOptional tags:\n\n* `t` (RECOMMENDED): `[\"t\", \"domain:<category>\"]` (e.g. `[\"t\", \"domain:plumbing\"]`). Enables relay-side discovery by domain via `#t` filters. The `domain` tag remains the canonical source; the `t` tag is a relay-filterable mirror.\n* `e` (OPTIONAL): Reference to the endorser's profile event (any kind).\n* `expiration` (OPTIONAL): NIP-40 timestamp. Forces periodic re-endorsement.\n\n### Weighting\n\nApps SHOULD weight endorsements by the endorser's track record:\n\n- **Verified interactions** - an endorser with 500 completed transactions carries more weight than one with 5. Zero-history endorser = zero weight (primary Sybil defence).\n- **Ratings** - higher-rated endorsers carry more weight.\n- **Category relevance** - same-category endorsements carry full weight; cross-category MAY be weighted at 50%.\n\n### Withdrawal\n\nRetract by publishing a new `kind:30517` with the same `d` tag and empty content. Apps MUST treat empty content as retracted.\n\n### REQ Filters\n\n```json\n[\n    {\"kinds\": [30517], \"#p\": [\"<endorsed-pubkey>\"]},\n    {\"kinds\": [30517], \"authors\": [\"<endorser-pubkey>\"]}\n]\n```\n\nFilter by `#p` at the relay, then post-filter by `domain` tag client-side. NIP-01 only defines relay-side filters for single-letter tag names.\n\n---\n\n## Composing with NIP-51\n\nThe following trust data types are modelled as NIP-51 lists rather than dedicated kinds. This section provides concrete JSON examples so implementers know exactly how to structure these events.\n\n### Trusted Provider List (NIP-51 kind 30000)\n\nA user's personal list of preferred providers, with per-entry category and trust rating. Publishing a new version replaces the previous list entirely.\n\n```json\n{\n    \"kind\": 30000,\n    \"pubkey\": \"<user-hex-pubkey>\",\n    \"created_at\": 1698700000,\n    \"tags\": [\n        [\"d\", \"trusted-providers\"],\n        [\"title\", \"Trusted Providers\"],\n        [\"p\", \"<provider-1-pubkey>\", \"plumbing\", \"5\", \"personal_experience\"],\n        [\"p\", \"<provider-2-pubkey>\", \"cleaning\", \"4\", \"recommendation\"],\n        [\"p\", \"<provider-3-pubkey>\", \"plumbing\", \"4\", \"personal_experience\", \"1742000000\"]\n    ],\n    \"content\": \"\",\n    \"id\": \"<32-byte-hex>\",\n    \"sig\": \"<64-byte-hex>\"\n}\n```\n\nEach `p` tag carries positional metadata:\n\n| Position | Description | Required |\n| -------- | ----------- | -------- |\n| 1 | Provider's hex pubkey | Yes |\n| 2 | Category for which this provider is trusted | Yes |\n| 3 | Personal trust rating (1-5) | Yes |\n| 4 | Trust reason | No |\n| 5 | Expiration (Unix timestamp) | No |\n\n#### Trust Reasons\n\n| Value | Description |\n| ----- | ----------- |\n| `personal_experience` | Trust earned through direct interaction (default if omitted) |\n| `recommendation` | Imported from a shareable recommendation list |\n| `social_proof` | Added because multiple contacts trust this provider |\n\n#### Time-Bound Trust\n\nPosition 5 carries an optional expiration timestamp. When the current time exceeds this value, the trust entry has lapsed. Clients MUST NOT treat expired entries as active trust. This supports trial periods: trust a new provider for a fixed window and decide later whether to make it permanent.\n\n#### Category-Scoped Entries\n\nA provider MAY appear multiple times with different categories. Each entry is independent; ratings, reasons, and expirations MAY differ per category. A provider trusted at 5 for plumbing may be trusted at 3 for electrical work.\n\n#### REQ Filters\n\n```json\n[\n    {\"kinds\": [30000], \"authors\": [\"<user-pubkey>\"], \"#d\": [\"trusted-providers\"]},\n    {\"kinds\": [30000], \"#p\": [\"<provider-pubkey>\"]}\n]\n```\n\n### Shareable Recommendations (NIP-51 kind 30000)\n\nWord-of-mouth provider recommendations. A user publishes a curated list that others can discover and import into their own trusted provider list.\n\nTwo visibility modes:\n\n- **`public`** - visible to anyone, shareable via link. \"Here are my 5 trusted cleaners.\"\n- **`private`** - NIP-44 encrypted content with specific recipients tagged. \"Here are my babysitters, sharing with my sister.\"\n\n```json\n{\n    \"kind\": 30000,\n    \"tags\": [\n        [\"d\", \"rec:my-london-plumbers\"],\n        [\"title\", \"My London Plumbers\"],\n        [\"domain\", \"plumbing\"],\n        [\"visibility\", \"public\"],\n        [\"p\", \"<provider-1-pubkey>\", \"plumbing\", \"5\"],\n        [\"p\", \"<provider-2-pubkey>\", \"plumbing\", \"4\"],\n        [\"expiration\", \"1742000000\"]\n    ],\n    \"content\": \"Plumbers I've used and trust. All South London, all reasonable prices.\",\n    \"id\": \"<32-byte-hex>\",\n    \"sig\": \"<64-byte-hex>\"\n}\n```\n\nThe `d` tag uses a `rec:` prefix to distinguish recommendation lists from trusted provider lists.\n\nFor private recommendations, the `content` field is NIP-44 encrypted to each recipient. Recipient pubkeys are tagged with a `recipient` marker:\n\n```json\n{\n    \"kind\": 30000,\n    \"tags\": [\n        [\"d\", \"rec:babysitters-for-sarah\"],\n        [\"title\", \"Babysitters for Sarah\"],\n        [\"domain\", \"childcare\"],\n        [\"visibility\", \"private\"],\n        [\"p\", \"<recipient-pubkey>\", \"recipient\"],\n        [\"expiration\", \"1742000000\"]\n    ],\n    \"content\": \"<NIP-44 encrypted JSON containing provider entries>\",\n    \"id\": \"<32-byte-hex>\",\n    \"sig\": \"<64-byte-hex>\"\n}\n```\n\n#### Import Flow\n\n1. App displays the recommendation with provider profiles.\n2. User selects which providers to import (explicit action REQUIRED; no automatic trust injection).\n3. App adds selected providers to user's trusted provider list (`kind:30000`, `d:trusted-providers`) with reason `recommendation`.\n\n### Provider Collective (NIP-51 kind 30000)\n\nA group of providers sharing clients and coordinating under a common identity. Solves the single-provider availability problem.\n\n```json\n{\n    \"kind\": 30000,\n    \"tags\": [\n        [\"d\", \"collective:south-london-emergency-plumbers\"],\n        [\"title\", \"South London Emergency Plumbers\"],\n        [\"L\", \"collective\"],\n        [\"l\", \"plumbing\", \"collective\"],\n        [\"p\", \"<founder-pubkey>\", \"admin\"],\n        [\"p\", \"<member-2-pubkey>\", \"admin\"],\n        [\"p\", \"<member-3-pubkey>\", \"member\"],\n        [\"p\", \"<member-4-pubkey>\", \"member\"],\n        [\"coverage\", \"gcpuu\"],\n        [\"coverage\", \"gcpuv\"]\n    ],\n    \"content\": \"24/7 emergency plumbing across South London. All background-checked and insured.\",\n    \"id\": \"<32-byte-hex>\",\n    \"sig\": \"<64-byte-hex>\"\n}\n```\n\nThe `d` tag uses a `collective:` prefix. The `L`/`l` label tags (per NIP-32) identify this list as a collective and carry the service category.\n\n#### Roles\n\n| Role | Permissions |\n| ---- | ----------- |\n| `admin` | Add/remove members, manage collective profile, delegate admin |\n| `member` | Accept tasks from collective's shared clients, publish availability under collective identity |\n\n#### Trusting a Collective\n\nUsers reference a collective in their trusted provider list by adding a `collective` tag:\n\n```json\n[\"collective\", \"collective:south-london-emergency-plumbers\", \"plumbing\", \"5\"]\n```\n\nPositions match the `p` tag format:\n\n| Position | Description | Required |\n| -------- | ----------- | -------- |\n| 1 | Collective's `d` tag identifier | Yes |\n| 2 | Category for which this collective is trusted | Yes |\n| 3 | Personal trust rating (1-5) | Yes |\n| 4 | Trust reason | No |\n| 5 | Expiration (Unix timestamp) | No |\n\nAny member of the trusted collective can then serve the user.\n\n#### Individual Reputation Preserved\n\nMembers keep their own ratings and profiles. The collective is a coordination layer, not a replacement for individual identity.\n\n### Block List (NIP-51 kind 10000)\n\nNIP-51 mute lists (`kind:10000`) handle blocking. For category-scoped blocking, use the encrypted content field to store structured block entries.\n\nThe mute list's public tags carry no blocked pubkeys. All block data is stored in the NIP-44 self-encrypted `content` field to prevent metadata leakage:\n\n```json\n{\n    \"kind\": 10000,\n    \"tags\": [],\n    \"content\": \"<NIP-44 self-encrypted JSON>\",\n    \"id\": \"<32-byte-hex>\",\n    \"sig\": \"<64-byte-hex>\"\n}\n```\n\n#### Encrypted Content Structure\n\n```json\n{\n    \"blocked\": [\n        {\n            \"pubkey\": \"<hex-pubkey>\",\n            \"blockedAt\": 1708444800,\n            \"reason\": \"no_show\",\n            \"category\": \"plumbing\",\n            \"note\": \"Three no-shows in a row\"\n        },\n        {\n            \"pubkey\": \"<hex-pubkey>\",\n            \"blockedAt\": 1708531200,\n            \"reason\": \"safety\",\n            \"note\": \"Aggressive behaviour\"\n        }\n    ],\n    \"updatedAt\": 1708531200\n}\n```\n\n#### Block Reason Codes\n\n| Code | Description |\n| ---- | ----------- |\n| `safety` | Felt unsafe, aggressive behaviour |\n| `no_show` | Repeated no-shows |\n| `harassment` | Unwanted contact |\n| `fraud` | Payment disputes, fraudulent claims |\n| `other` | Free-text note explains |\n\n#### Behavioural Rules\n\n1. Apps SHOULD filter incoming requests and offers against the block list before presenting them.\n2. Blocking is silent; no notification is sent.\n3. Entries without a `category` field block across all categories.\n4. Entries with a `category` field apply to that category only.\n5. Cross-category blocks take precedence over category-scoped blocks.\n\n---\n\n## Social Graph Discovery\n\nNIP-TRUST kinds and NIP-51 trust lists together enable a trust discovery algorithm using existing Nostr data:\n\n| Tier | Source | Priority |\n| ---- | ------ | -------- |\n| 1 | Providers in user's NIP-51 trusted provider list | Highest |\n| 2 | Providers in user's NIP-02 follow list (`kind:3`) | High |\n| 3 | Providers endorsed (`kind:30517`) by Tier 1 providers | Medium |\n| 4 | Providers followed by user's follows (2-hop web of trust) | Low |\n| 5 | Any available provider meeting minimum criteria | Default fallback |\n\nApps SHOULD present the trust tier alongside provider listings so users understand the source of trust.\n\n---\n\n## Protocol Flow\n\n\n![Trust Network Flow](https://raw.githubusercontent.com/forgesworn/nip-drafts/main/images/trust-1.png)\n\n```mermaid\nsequenceDiagram\n    participant A as Provider A (established)\n    participant B as Provider B (new)\n    participant U as User\n    participant R as Relay\n\n    Note over A,B: Endorsement builds trust bridge\n    A->>R: kind:30517 endorsement for B (skill)\n    R-->>U: User discovers endorsement\n\n    Note over U: User hires B based on endorsement\n    U->>R: kind:30000 add B to trusted providers (reason: social_proof)\n\n    Note over U,B: Later: trust breakdown\n    U->>R: kind:30515 revocation (reason: quality_decline)\n    U->>R: kind:30000 remove B from trusted providers\n    R-->>B: NIP-17 notification (reason code only)\n\n    Note over A: Endorser reviews revocation signal\n    A->>R: kind:30517 empty content (withdrawal)\n```\n\n---\n\n## Sybil Resistance Properties\n\nNIP-TRUST provides structural sybil resistance through several mechanisms.\n\n### Endorsement Cost\nCreating a provider endorsement (`kind:30517`) requires an existing keypair with reputation history. An attacker must either:\n- Build genuine reputation over time (expensive)\n- Compromise an existing trusted keypair (difficult)\n- Create a new keypair with no endorsement weight (ineffective)\n\n### Collective Membership\nProvider collectives require approval from existing members. A sybil attacker cannot join established collectives without social verification.\n\n### Trust Decay\nTrust lists are actively maintained. Stale entries lose weight in discovery algorithms. An attacker who creates fake trust relationships must continuously maintain them.\n\n### Graph Analysis\nThe trust graph is public (trust lists, endorsements, collectives are all on relays). Clients can detect suspicious patterns:\n- Clusters of new keypairs endorsing each other\n- Trust relationships with no corresponding transaction history\n- Keypairs that only endorse and never transact\n\n### What NIP-TRUST Does NOT Prevent\n- A well-resourced attacker building genuine reputation over months\n- Collusion between existing trusted parties\n- Social engineering of collective membership\n\nThese are inherent limits of any decentralised trust system. NIP-TRUST raises the cost of sybil attacks without requiring a central authority.\n\n---\n\n## Use Cases Beyond Service Providers\n\n### Content Moderation Networks\nRelay operators maintain trusted curator lists (NIP-51 `kind:30000`). Content from endorsed keypairs gets priority. New accounts must earn endorsements before their content surfaces.\n\n### Recommendation Circles\nFriends share recommendation lists. NIP-51 collectives become curated recommendation groups.\n\n### Professional Endorsements\nLinkedIn-style endorsements on Nostr. A developer's endorsement (`kind:30517`) from a known open-source maintainer carries weight. The endorsement is portable; it follows the keypair, not a platform.\n\n### Academic Peer Review\nResearchers form collectives (NIP-51 lists) for peer review groups. Trust lists track which reviewers are trusted in which domains. Endorsements signal expertise areas.\n\n---\n\n## Security Considerations\n\n* **No automatic trust injection.** Importing recommendations requires explicit user action. Apps MUST NOT silently add providers to trust lists.\n* **Self-encrypted block lists.** Block data is NIP-44 self-encrypted within `kind:10000` mute lists; relays cannot read who is blocked.\n* **Tiered revocation visibility.** Safety-related revocations are visible to platform operators for pattern detection; personal preference revocations are private.\n* **Sybil resistance for endorsements.** Apps SHOULD weight endorsements by the endorser's track record (verified interactions, ratings). Zero-history endorsers carry zero weight.\n* **Expiration support.** Trust entries and endorsements support NIP-40 expiration for time-bounded relationships.\n* **Revocation is not deletion.** A `kind:30515` trust revocation is a permanent, timestamped signal. It cannot be silently undone. To restore trust, the revoking party publishes a new endorsement or re-adds the provider to their trust list. The revocation history remains queryable.\n\n## Privacy\n\n* **Block lists are fully encrypted.** Blocked pubkeys MUST NOT appear in public tags. All block data is stored in NIP-44 self-encrypted content within the `kind:10000` mute list.\n* **Revocation content is encrypted.** Free-text reasons in `kind:30515` are NIP-44 encrypted to relevant platform operators. The revoked party receives only the reason code via NIP-17, never the free-text.\n* **Private recommendations use NIP-44.** When visibility is `private`, recommendation list content is NIP-44 encrypted to specified recipients.\n* **Trust lists reveal social graph.** Public NIP-51 trust lists and `kind:30517` endorsements are visible on relays. Users concerned about social graph exposure SHOULD use NIP-44 encrypted content within their NIP-51 lists, keeping `p` tags in the encrypted payload rather than public tags.\n\n## Test Vectors\n\n### Kind 30515 - Trust Revocation\n\n```json\n{\n  \"kind\": 30515,\n  \"pubkey\": \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\",\n  \"created_at\": 1709740800,\n  \"tags\": [\n    [\"d\", \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2:b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3:plumbing:1709740800\"],\n    [\"p\", \"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\"],\n    [\"alt\", \"Trust revocation: quality decline in plumbing\"],\n    [\"domain\", \"plumbing\"],\n    [\"t\", \"domain:plumbing\"],\n    [\"reason_code\", \"quality_decline\"],\n    [\"e\", \"dddd4444eeee5555ffff6666aaaa1111bbbb2222cccc3333dddd4444eeee5555\"]\n  ],\n  \"content\": \"<NIP-44 encrypted to platform operator(s): 'Quality dropped significantly over last 3 jobs.'>\",\n  \"id\": \"<32-byte-hex>\",\n  \"sig\": \"<64-byte-hex>\"\n}\n```\n\n### Kind 30517 - Provider Endorsement\n\n```json\n{\n  \"kind\": 30517,\n  \"pubkey\": \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\",\n  \"created_at\": 1709740800,\n  \"tags\": [\n    [\"d\", \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2:b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3:plumbing\"],\n    [\"p\", \"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\"],\n    [\"alt\", \"Provider endorsement: skill in plumbing\"],\n    [\"domain\", \"plumbing\"],\n    [\"t\", \"domain:plumbing\"],\n    [\"endorsement_type\", \"skill\"],\n    [\"e\", \"dddd4444eeee5555ffff6666aaaa1111bbbb2222cccc3333dddd4444eeee5555\"]\n  ],\n  \"content\": \"Worked alongside Mo for 3 years. Solid work, reliable, always on time.\",\n  \"id\": \"<32-byte-hex>\",\n  \"sig\": \"<64-byte-hex>\"\n}\n```\n\n### NIP-51 Trusted Provider List\n\n```json\n{\n  \"kind\": 30000,\n  \"pubkey\": \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\",\n  \"created_at\": 1709740800,\n  \"tags\": [\n    [\"d\", \"trusted-providers\"],\n    [\"title\", \"Trusted Providers\"],\n    [\"p\", \"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\", \"plumbing\", \"5\", \"personal_experience\"],\n    [\"p\", \"c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\", \"cleaning\", \"4\", \"recommendation\"]\n  ],\n  \"content\": \"\",\n  \"id\": \"<32-byte-hex>\",\n  \"sig\": \"<64-byte-hex>\"\n}\n```\n\n### NIP-51 Block List\n\n```json\n{\n  \"kind\": 10000,\n  \"pubkey\": \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\",\n  \"created_at\": 1709740800,\n  \"tags\": [],\n  \"content\": \"<NIP-44 self-encrypted JSON>\",\n  \"id\": \"<32-byte-hex>\",\n  \"sig\": \"<64-byte-hex>\"\n}\n```\n\n## Dependencies\n\n* [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md): Basic protocol flow, addressable events\n* [NIP-02](https://github.com/nostr-protocol/nips/blob/master/02.md): Contact lists (social graph discovery)\n* [NIP-09](https://github.com/nostr-protocol/nips/blob/master/09.md): Deletion events (right to erasure)\n* [NIP-17](https://github.com/nostr-protocol/nips/blob/master/17.md): Gift wrap (private notifications)\n* [NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md): Expiration timestamps\n* [NIP-44](https://github.com/nostr-protocol/nips/blob/master/44.md): Versioned encrypted payloads\n* [NIP-51](https://github.com/nostr-protocol/nips/blob/master/51.md): Lists (trusted providers, recommendations, collectives, block lists)\n\n## Reference Implementation\n\nNo public reference implementation exists yet. Implementors SHOULD refer to the kind definitions and NIP-51 composition examples above.\n\nA minimal implementation requires:\n\n1. A Nostr client that supports addressable event publishing, NIP-51 list management, and NIP-02 contact list queries.\n2. A NIP-44 encryption library for self-encrypting block list content and private recommendation payloads.\n3. Social graph traversal logic implementing the 5-tier discovery algorithm described above.","sig":"97242dadae485bec8d861a491ff7bc99509d154e86d446a1054120a97809ed98935c5962dc6b33a74bb92dbfc9693fa49886d638122e71ce5d7fcf2f0311595c"}