NIP-91: Service Attestations
NIP-91: Service Attestations (with optional Namecoin-Anchored Identity Binding)
draft optional
Abstract
This NIP defines a protocol for signed attestations of service or task completion between Nostr identities, forming a portable, queryable reputation layer. It introduces two new event kinds: one for publishing attestation claims and one for aggregating attestation sets. It also specifies an optional Namecoin identity anchor mechanism, whereby the Nostr pubkey receiving an attestation MUST have been the active value associated with a Namecoin id/ name at the time the attested service occurred, providing a blockchain-timestamped binding between human-readable names and reputation history.
Motivation
Existing NIPs provide building blocks adjacent to reputation but none cover the specific use case of structured, verifiable attestations for services and tasks performed between parties:
| Existing NIP | What it covers | Gap this NIP fills |
|---|---|---|
| NIP-58 (Badges) | Issuer-defined badges awarded to pubkeys | Badges are binary (awarded/not); they lack structured ratings, service context, or temporal proof of identity binding. A badge says "you earned X" but not "you performed service Y for me on date Z and I rate it 4.5/5." |
| NIP-32 (Labeling) | Generic labels on events/pubkeys/relays | Labels are categorical metadata for moderation and classification. They have no rating scale, no service/task context, and no concept of a bilateral transaction. |
| NIP-56 (Reporting) | Negative reports on content or users | One-directional negative signaling only. No positive attestation, no rating spectrum, no service context. |
| NIP-85 (Trusted Assertions) | WoT score computation by service providers | Addresses computed aggregations by third-party providers, not first-party attestation events between transacting parties. Complementary but upstream of this NIP. |
| NIP-39 (External Identities) | Linking external platform accounts | Proves account ownership on other platforms but carries no reputation or attestation data. |
| PR #1208 (NIP-77, Trust) | Expressing trust between pubkeys | Generic trust/distrust expression. Not tied to specific services, transactions, or tasks. No Namecoin anchoring. |
| PR #1515 (Reviews) | Review events with ratings | Closest prior art. Focuses on consumer reviews of locations/products/content. Does not address bilateral service attestation, Namecoin anchoring, or the temporal identity proof mechanism defined here. |
| PR #46 (Reputation) | PoW-weighted reputation assignment | Never merged. Uses proof-of-work as weight signal. No service/task context, no identity anchoring. |
Specification
Event Kinds
| Kind | Name | Description |
|---|---|---|
38383 | Service Attestation | A signed attestation that a pubkey performed a service or task |
38384 | Attestation Set (parameterized replaceable) | A user-maintained list of attestations they currently stand behind |
Kind numbers are provisional pending number assignment.
Kind 38383: Service Attestation
A Service Attestation is a parameterized replaceable event published by the attester (the party who received or observed the service) about the attestee (the party who performed the service). Using a d tag makes it replaceable, allowing the attester to update their rating over time.
{
"kind": 38383,
"pubkey": "<attester pubkey (hex)>",
"created_at": <unix timestamp>,
"tags": [
["p", "<attestee pubkey (hex)>", "<recommended relay URL>"],
["d", "<unique attestation identifier>"],
["service", "<service category>", "<optional subcategory>"],
["rating", "<score>", "<max>"],
["completed_at", "<unix timestamp of service completion>"],
["ref", "<optional: event ID, URL, or external identifier for the underlying transaction>"],
["nmc", "<namecoin name>", "<block height at service time>"],
["L", "nip-XX.service"],
["l", "<service category>", "nip-XX.service"]
],
"content": "<optional free-text review or context>",
"sig": "<signature>"
}Required Tags
- **
p** — The pubkey of the attestee (service performer). Relay hint RECOMMENDED per NIP-01. - **
d** — A unique identifier for this attestation, chosen by the attester. This makes the event parameterized-replaceable, allowing the attester to update their rating over time. - **
service** — A short, lowercase, dot-separated service category string. The first value is the primary category; the optional second value is a subcategory. Examples: ["service", "plumbing.repair"]["service", "software.frontend"]["service", "hospitality.hosting"]["service", "commerce.sale"]["service", "education.tutoring"]["service", "transport.delivery"]- **
rating** — A two-element value: the score and the maximum. Both MUST be non-negative numbers. Clients SHOULD normalize to a 0–1 scale for aggregation. ["rating", "4.5", "5"]→ 0.9 normalized["rating", "92", "100"]→ 0.92 normalized["rating", "1", "1"]→ binary positive attestation
Optional Tags
- **
completed_at** — Unix timestamp of when the service or task was completed. If omitted,created_atis used. This is important when an attestation is published some time after the service. - **
ref** — A reference to the underlying transaction. Can be: - An
etag (Nostr event ID) for services negotiated on-Nostr - A URL for an external reference
- An
itag per NIP-39 conventions for external content IDs - **
nmc** — Namecoin anchor (see Namecoin Identity Anchoring below). - **
Landl** — NIP-32 namespace labels. RECOMMENDED for discoverability via relay label queries.
Content
The content field is an optional free-text review. It MAY be empty. Clients SHOULD render it as a comment alongside the structured rating data.
Kind 38384: Attestation Set
An Attestation Set is a parameterized replaceable event (per NIP-01) that allows a user to maintain a curated list of attestations they currently endorse. This addresses the reality that opinions change — a service that was once five stars may degrade, or vice versa.
{
"kind": 38384,
"pubkey": "<attester pubkey (hex)>",
"created_at": <unix timestamp>,
"tags": [
["d", "active_attestations"],
["a", "38383:<attestee pubkey>:<d-tag>", "<relay hint>"],
["a", "38383:<attestee pubkey>:<d-tag>", "<relay hint>"],
...
],
"content": "",
"sig": "<signature>"
}The a tags reference the attester's own Service Attestation events. Clients MAY treat only attestations present in the most recent Attestation Set as the attester's current active endorsements. Attestation events that exist but are absent from the set SHOULD be treated as withdrawn (no longer reflecting the attester's current opinion).
If an attester has never published an Attestation Set, all of their Service Attestation events SHOULD be treated as active.
Optional Namecoin Identity Anchoring
Overview
This section defines an optional mechanism for binding Nostr attestation history to a Namecoin id/ name with temporal proof. It uses Namecoin's existing identity namespace and blockchain timestamps to establish that a pubkey was the declared identity key for a human-readable name at the time a service was performed.
Namecoin id/ Value Format Extension
To participate in this system, a Namecoin id/ name SHOULD include a nostr field in its JSON value:
{
"nostr": "<nostr pubkey hex>",
"email": "[email protected]",
"bitcoin": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
}Or, for multiple pubkeys (e.g., primary and delegation):
{
"nostr": {
"default": "<primary nostr pubkey hex>",
"signing": "<delegated signing pubkey hex>"
}
}Note on value size: Namecoin values are limited to 520 bytes. A Nostr pubkey in hex is 64 characters. A minimal value of
{"nostr":"<64 hex chars>"}is approximately 76 bytes, well within limits.
The nmc Tag
When a Service Attestation includes an nmc tag, the attester is claiming that the attestee's pubkey was associated with the specified Namecoin name at the time of service completion:
["nmc", "id/alice", "850000"]- First value: The full Namecoin name including namespace prefix (e.g.,
id/alice). - Second value: The Namecoin block height at (or nearest before) the
completed_attimestamp. This serves as a checkpoint for verification.
Verification Procedure
A client or verifier performing Namecoin-anchored attestation verification MUST follow these steps:
- Retrieve the attestee's pubkey from the
ptag of the Service Attestation event.
- **Retrieve the
completed_attimestamp** (orcreated_atifcompleted_atis absent).
- **Parse the
nmctag** to obtain the Namecoin name and reference block height.
- Query Namecoin history for the specified name at the specified block height. This requires access to a Namecoin full node or a trusted API that can return historical name values:
`` namecoind name_history "id/alice" ` The verifier must find the name_update` transaction that was active (i.e., most recently confirmed before) the reference block height.
- **Extract the
nostrfield** from the Namecoin name value that was active at that block height.
- Compare pubkeys. The Nostr pubkey in the
ptag of the attestation MUST match thenostrpubkey value in the Namecoin name record at the reference block height.
- Validate temporal bounds:
- The reference block height MUST correspond to a block whose timestamp is ≤ the
completed_attimestamp of the attestation. - The name MUST NOT have been expired at the reference block height (Namecoin names expire after 35,999 blocks without renewal).
- Result: If all checks pass, the attestation is Namecoin-verified. Clients MAY display a distinct visual indicator (e.g., a chain-link icon, a colored badge) to distinguish Namecoin-verified attestations from unanchored ones.
Temporal Gap Tolerance
Because Namecoin blocks occur approximately every 10 minutes and name updates require 12-block confirmation, there is inherent latency between a pubkey change and its on-chain finality. Clients SHOULD allow a tolerance window of ±12 blocks (~2 hours) around the reference block height when matching timestamps.
Key Rotation Handling
When a Namecoin id/ name updates its nostr value to a new pubkey (key rotation), attestations signed during the previous key's validity period remain valid if and only if they reference a block height during which the previous key was active. This is by design: the Namecoin chain preserves the full history of name values, so historical attestations are always verifiable against the key that was active at their timestamp.
Clients SHOULD indicate when an attestation references a pubkey that is no longer the current value for a Namecoin name, e.g., "Verified at time of service (key since rotated)."
Why Namecoin anchoring matters
Nostr pubkeys are pseudonymous and can be generated freely. When reputation has economic value — for example, a contractor's track record of completed jobs — there is an incentive to fabricate attestation histories for freshly generated keys and then associate those keys with a human-readable identity after the fact.
Namecoin's d/ and id/ namespace provides a tamper-evident, temporally ordered binding between human-readable names and pubkeys. Because Namecoin name updates are recorded on a merge-mined blockchain with Bitcoin-class security, a verifier can confirm that a given pubkey was actually the declared identity of a Namecoin name at the time a service attestation was issued. This prevents backdating reputation to a name that didn't hold that key at the relevant time.
This is opt-in. Attestations without Namecoin anchoring are fully valid and useful. The Namecoin layer adds a higher tier of assurance for use cases where temporal identity provenance matters (marketplaces, professional services, credentialing).
Querying and Aggregation
Relay Filters
Clients can query for attestations using standard NIP-01 filters:
// All attestations about a specific pubkey
{"kinds": [38383], "#p": ["<attestee pubkey>"]}
// All attestations in a specific service category
{"kinds": [38383], "#l": ["plumbing.repair"]}
// All attestations by a specific attester
{"kinds": [38383], "authors": ["<attester pubkey>"]}
// All Namecoin-anchored attestations about a pubkey
{"kinds": [38383], "#p": ["<attestee pubkey>"], "#nmc": ["id/alice"]}Client-Side Aggregation
Reputation computation is explicitly left to clients, consistent with Nostr's philosophy that interpretation is a client concern. However, this NIP RECOMMENDS the following approach:
- Web-of-Trust weighting. Attestations from pubkeys closer in the client user's social graph (per follow lists, NIP-02) SHOULD carry more weight than attestations from distant or unknown pubkeys. See the discussion in PR #46 for the rationale: social distance matters more than proof-of-work or payment for anti-sybil purposes.
- Namecoin-verified premium. Clients MAY give higher weight to attestations with valid Namecoin anchoring, as they provide stronger identity assurance.
- Temporal decay. More recent attestations SHOULD be weighted more heavily than old ones, as service quality can change.
- Attestation Set filtering. If the attester maintains an Attestation Set (kind
38384), only attestations referenced in the latest set SHOULD be considered active.
NIP-85 Integration
This NIP is designed to be upstream of NIP-85 (Trusted Assertions). A NIP-85 service provider can:
- Ingest Service Attestation events (kind
38383) - Perform Namecoin verification on
nmc-tagged events - Compute aggregate reputation scores using WoT, PageRank, or other algorithms
- Publish results as NIP-85 Trusted Assertion events (kind
30382)
This keeps the first-party attestation data (this NIP) cleanly separated from computed reputation scores (NIP-85).
Security Considerations
Sybil Attacks
An attacker can generate many keypairs and have them attest to each other. Defenses:
- WoT filtering is the primary defense. Attestations from unknown pubkeys carry no weight by default.
- Namecoin anchoring raises the cost of sybil identities (each name requires NMC and ongoing renewal fees).
- NIP-13 proof-of-work MAY optionally be required by relays or weighted by clients.
Collusion
Two parties can exchange fake positive attestations. Defenses:
- Graph analysis by NIP-85 providers can detect cliques of mutual attestation with no outside connections.
- Zap receipts (NIP-57) referenced via the
reftag provide evidence of actual economic transactions underlying attestations.
Namecoin Reorg Risk
Deep Namecoin chain reorganizations could invalidate historical name-to-pubkey bindings. In practice, Namecoin is merge-mined with Bitcoin and has not experienced a significant reorg in years. Clients SHOULD treat attestations referencing block heights older than 100 blocks as having negligible reorg risk.
Stale Namecoin Names
A Namecoin name that has expired (not renewed within 35,999 blocks) loses its binding. Clients MUST check expiry status and SHOULD flag attestations whose nmc reference points to an expired name period.
Examples
Example 1: Simple Service Attestation (No Namecoin)
Alice attests that Bob did a good job fixing her plumbing:
{
"kind": 38383,
"pubkey": "aaa111...",
"created_at": 1711000000,
"tags": [
["p", "bbb222...", "wss://relay.example.com"],
["d", "alice-bob-plumbing-2026-03"],
["service", "plumbing.repair"],
["rating", "5", "5"],
["completed_at", "1710900000"],
["L", "nip-XX.service"],
["l", "plumbing.repair", "nip-XX.service"]
],
"content": "Fixed the kitchen sink leak quickly and cleanly. Would hire again.",
"sig": "..."
}Example 2: Namecoin-Anchored Attestation
Charlie attests that id/dana (Namecoin name) performed excellent frontend development. At the time of the work, the id/dana name pointed to pubkey ddd444...:
{
"kind": 38383,
"pubkey": "ccc333...",
"created_at": 1711000000,
"tags": [
["p", "ddd444...", "wss://relay.example.com"],
["d", "charlie-dana-frontend-2026-q1"],
["service", "software.frontend"],
["rating", "95", "100"],
["completed_at", "1710500000"],
["ref", "https://github.com/project/pull/42"],
["nmc", "id/dana", "849500"],
["L", "nip-XX.service"],
["l", "software.frontend", "nip-XX.service"]
],
"content": "Delivered the React dashboard ahead of schedule. Clean code, great communication.",
"sig": "..."
}Verification: A client queries Namecoin for name_history "id/dana", finds that at block 849500 the value was {"nostr":"ddd444..."}, confirms this matches the p tag, and marks the attestation as Namecoin-verified.
Example 3: Attestation Set
Alice maintains her active endorsements:
{
"kind": 38384,
"pubkey": "aaa111...",
"created_at": 1711100000,
"tags": [
["d", "active_attestations"],
["a", "38383:bbb222...:alice-bob-plumbing-2026-03", "wss://relay.example.com"],
["a", "38383:eee555...:alice-eve-tutoring-2025", "wss://relay.example.com"]
],
"content": "",
"sig": "..."
}Alice had previously attested to a third party, but has removed that a tag — indicating she no longer stands behind that attestation.
Service Category Registry
To promote interoperability, clients SHOULD use categories from this initial registry. New categories MAY be added by convention; clients SHOULD attempt to match existing categories before creating new ones.
| Category | Subcategories (examples) |
|---|---|
commerce | sale, trade, rental |
software | frontend, backend, mobile, devops, security |
plumbing | repair, installation, inspection |
electrical | repair, installation, inspection |
hospitality | hosting, lodging, dining |
transport | delivery, rideshare, freight |
education | tutoring, mentoring, course |
creative | design, writing, music, video |
legal | consultation, representation, review |
finance | consultation, accounting, audit |
health | consultation, therapy, fitness |
general | task, errand, consultation |
Clients MAY use NIP-32 labeling conventions to propose and discover new categories in the wild.
Backward Compatibility
This NIP introduces new event kinds and does not modify any existing kinds or behavior. Clients and relays that do not implement this NIP will simply ignore these event kinds, per standard NIP-01 behavior.
The nmc tag is a new tag and will be ignored by clients that do not support Namecoin anchoring. The attestation remains fully valid and useful without it.
NIP-32 L/l tags are included for compatibility with existing label-based discovery. NIP-85 integration is purely additive.
References
- NIP-01: Basic Protocol
- NIP-02: Follow List
- NIP-13: Proof of Work
- NIP-32: Labeling
- NIP-39: External Identities
- NIP-57: Lightning Zaps
- NIP-58: Badges
- NIP-85: Trusted Assertions
- Namecoin Identity Namespace
- Namecoin FAQ
Comparison with Wiki-Attestations (NostrHub NIP)
This is a comparison between the Wiki-Attestations NIP and the Service-Attestations NIP above.
The two proposals solve different problems with different architectures. The NostrHub wiki article ("Wiki-Attestations") is a general-purpose truth-claim framework for any Nostr event. Our draft ("Service-Attestations") is a domain-specific reputation protocol for service/task interactions with a blockchain identity anchoring layer. They overlap in the middle but diverge at both ends.
Here's the breakdown across every major dimension:
1. Scope and Philosophy
Wiki-Attestations is deliberately abstract — it answers "is this Nostr event true?" for any event kind. Someone publishes a claim (the "Assertion Event"), and a third-party attestor verifies it. It's a generic truthfulness layer.
Service-Attestations is narrowly scoped — it answers "how did this person perform in a transaction?" It's a reputation/review primitive for commerce and services.
Wiki-Attestations could theoretically be used to build Service-Attestations on top of it, but it doesn't provide the domain-specific vocabulary (ratings, roles, bilateral structure) needed to do so without additional specification.
2. Event Kinds and Architecture
This is a major structural difference.
Wiki-Attestations defines four event kinds across a full lifecycle:
- Kind
31871— the attestation itself (addressable/replaceable) - Kind
31872— attestation request - Kind
31873— attestor recommendation - Kind
11871— attestor proficiency declaration
This is a rich system with a request-response flow — you can ask someone to verify your claim, they can declare what they're good at verifying, and third parties can recommend attestors.
Service-Attestations defines two kinds:
- Kind
38383— Service Attestation (parameterized replaceable) - Kind
38384— Attestation Set (parameterized replaceable)
It relies on NIP-32's existing label vocabulary convention for semantic structure. There's no request-response flow, no attestor discovery mechanism, and no proficiency declarations. It's deliberately minimal.
The replaceability difference is architecturally significant. Wiki-Attestations uses addressable events (the d tag makes them replaceable), which means an attestation can be updated or revoked by publishing a new event with the same d tag. Service-Attestations also uses parameterized replaceable events, allowing the attester to update their rating over time, and introduces Attestation Sets for managing which attestations are currently active.
3. What Gets Attested
Wiki-Attestations attests to events — the e, a, or p tag points to an existing Nostr event or pubkey, and the attestor is saying "this event/claim is valid or invalid." It has a formal validity model with valid/invalid values and temporal bounds (valid_from, valid_to). This is essentially a certificate model.
Service-Attestations attests to people's behavior in transactions — the p tag points to a counterparty, and the labels describe what happened (completed, failed, disputed) and the subject's role (provider, client, mediator). The e/a tags optionally link to the service event but aren't the focus — the person is.
4. Lifecycle and State Management
Wiki-Attestations has a full state machine: accepted → verifying → verified → revoked (or rejected). This is powerful for use cases like certificate verification, safety inspections, or credential validation where an attestation goes through a workflow. The revocation model is clean — publish a new event with the same d tag and ["s", "revoked"].
Service-Attestations has no lifecycle. An attestation is published once and stands as a permanent record (though it can be updated via replaceability). This is appropriate for reviews (you don't "verify" a review, you just read it) but would be inadequate for the safety-inspection-style use cases Wiki-Attestations targets.
5. Bilateral vs. Third-Party Model
This is the sharpest divergence.
Wiki-Attestations is fundamentally a third-party verification model: an attestor (distinct from the assertor) verifies someone else's claim. The attestor and assertor are different entities by design. This maps well to certificate authorities, auditors, inspectors, and credential issuers.
Service-Attestations is fundamentally a bilateral peer review model: both parties to a transaction attest to each other, linked by a shared d tag. Alice reviews Bob as a provider, Bob reviews Alice as a client. The mutual attestation pattern, where both parties reference the same engagement ID, is the primary trust signal. There's no concept of a third-party verifier in the base spec.
6. Sybil Resistance and Identity Anchoring
Wiki-Attestations doesn't address Sybil resistance directly. It mentions NIP-03 (OpenTimestamps) for timestamping and NIP-58 (Badges) as complementary, but there's no mechanism to make attestations expensive to forge or to bind identities to external systems. The implicit assumption is that the attestor's reputation in the viewer's WoT is sufficient.
Service-Attestations has a detailed Namecoin anchoring extension with a full verification algorithm, temporal binding requirements, failure modes, and a NIP-39 extension for profile linking. It also suggests Lightning payment proof (bolt11 tag) and NIP-57 zap linkage as economic Sybil resistance. This is the most novel part of the spec and has no equivalent in Wiki-Attestations.
7. Attestor Discovery
Wiki-Attestations has a sophisticated attestor discovery mechanism through kind 31873 (recommendations) and kind 11871 (proficiency declarations). An attestor can say "I'm good at verifying safety claims" and others can recommend them. This creates a marketplace of verification services.
Service-Attestations has no attestor discovery. It doesn't need one — there's no concept of a professional verifier. Everyone is both a potential attestor and subject.
8. Payment Integration
Wiki-Attestations includes a cashu_token tag on attestation requests, enabling payment-for-verification flows. You could lock a Cashu token to the condition that the attestor publishes a valid attestation. This is a compelling primitive for paid verification services.
Service-Attestations includes bolt11 as a payment proof tag (evidence the transaction happened) but not as a payment-for-attestation mechanism. The economic signal is backward-looking ("we transacted") not forward-looking ("pay me to verify").
9. Relationship to Existing NIPs
Both reference NIP-40 (expiration) and NIP-58 (badges).
Wiki-Attestations additionally leans on NIP-03 (OpenTimestamps) for blockchain anchoring — a lighter touch than the full Namecoin verification algorithm in Service-Attestations.
Service-Attestations leans heavily on NIP-32 (labeling) for its vocabulary convention, NIP-39 for identity linking, NIP-85 as a consumer of attestation data, and NIP-99 (classified listings) as a source of service events.
10. What Each Is Missing
Wiki-Attestations lacks:
- Domain-specific vocabulary for commerce/services
- Bilateral attestation patterns
- Numeric ratings
- Role semantics
- Sybil resistance mechanisms
- Reputation aggregation guidance
If you tried to build a marketplace reputation system on it, you'd need to define all of these yourself.
Service-Attestations lacks:
- A request-response workflow
- Attestor discovery and proficiency declarations
- Revocation (it relies on replaceability + Attestation Sets rather than state changes)
- The general ability to attest to arbitrary event truthfulness
- The paid-verification primitive
Bottom Line
These two proposals are more complementary than competing. Wiki-Attestations is infrastructure — a general-purpose truth-claim layer that could underpin many applications. Service-Attestations is an application — a specific reputation protocol for a specific use case (commerce), with a specific anchoring mechanism (Namecoin).
The strongest version of both would be to build Service-Attestations' domain vocabulary and Namecoin anchoring as an application profile on top of Wiki-Attestations' base event structure. You'd use kind 31871 as the attestation container, add the L/l label vocabulary for service semantics, add the rating and nmc tags as extensions, and define a convention where bilateral attestations share a d tag. This would give you the lifecycle management and attestor discovery of Wiki-Attestations plus the domain specificity and Sybil resistance of Service-Attestations.
Links
The full Service Attestation NIP draft can also be found here: https://gist.github.com/mstrofnone/5b40542c902069ed7e87ed96f93c1482