{"id":"fe59e81fdcb4dd7f2fa8218534adb7c338f6e35f82144f7dfe068838f3af3482","pubkey":"da19f1cd34beca44be74da4b306d9d1dd86b6343cef94ce22c49c6f59816e5bd","created_at":1774618290,"kind":30817,"tags":[["title","NIP-VARIATION: Scope & Price Change Management"],["k","30579"],["d","nip-variation"]],"content":"NIP-VARIATION\n=============\n\nScope & Price Change Management\n----------------------------------\n\n`draft` `optional`\n\nOne addressable event kind for proposing changes to agreed work on Nostr. Applications MAY compose with NIP-QUOTE for pricing context and NIP-APPROVAL for multi-party sign-off, but NIP-VARIATION works independently.\n\n> **Design principle:** The Variation Request records that a change was proposed and describes its scope. It does not price the change or approve it. Pricing composes OPTIONALLY with NIP-QUOTE (kind 30530); approval composes OPTIONALLY with NIP-APPROVAL (kinds 30570-30571). The consuming application updates its internal state based on the approved variation.\n\n> **Standalone.** This NIP works independently on any Nostr application.\n\n## Motivation\n\nNostr has events for creating agreements (NIP-99 listings, NIP-15 marketplace orders, NIP-ESCROW payment terms) but no standard mechanism for **changing the terms of an existing agreement**. In practice, scope changes are inevitable:\n\n- **Contract modifications** -- adding, removing, or substituting deliverables mid-project\n- **Order changes** -- modifying a marketplace order after acceptance\n- **Schedule adjustments** -- changing deadlines or milestones for ongoing work\n- **Price renegotiation** -- adjusting pricing based on changed circumstances\n\nWithout a standard, applications handle changes informally (DMs, new events that break the original reference chain) or not at all. NIP-VARIATION provides a single event kind for the change proposal itself. Pricing the change uses NIP-QUOTE; approving or rejecting it uses NIP-APPROVAL. This composition avoids inventing bespoke quote and approval semantics when proven primitives already exist.\n\n## Relationship to Existing NIPs\n\n### NIP-QUOTE (kinds 30530-30531)\n\nWhen a variation has a price impact, the provider publishes a NIP-QUOTE Quote (kind 30530) referencing the Variation Request via `e` tag. The Quote's `amount` represents the price delta (positive for cost increases, negative amounts expressed as a separate `credit` breakdown item for reductions). `breakdown` tags show what changed. Payment Terms (kind 30531) MAY follow if the variation changes the payment structure.\n\n### NIP-APPROVAL (kinds 30570-30571)\n\nVariation approval uses NIP-APPROVAL. An Approval Gate (kind 30570) references the Variation Request via `e` tag, and optionally references the Quote as well. The counterparty responds with an Approval Response (kind 30571). Multi-reviewer gates work naturally: if both parties and a project manager must sign off, the gate lists all three as `gate_authority`.\n\n### NIP-ESCROW\n\nIf the variation changes the total amount, the Lock (kind 30532) MAY need to be updated. Applications SHOULD handle this by creating a supplementary Lock for the delta, referencing the original Lock and the approved Variation Request.\n\n## Kinds\n\n| kind  | description         |\n| ----- | ------------------- |\n| 30579 | Variation Request   |\n\nAddressable event (NIP-01). The `d` tag format ensures each event occupies a unique slot, allowing updates via republication.\n\n---\n\n## Variation Request (`kind:30579`)\n\nPublished by either party to request a change to the agreed scope. Addressable; the proposer can update the request before a quote or approval response is received.\n\n```json\n{\n    \"kind\": 30579,\n    \"pubkey\": \"<requester-hex-pubkey>\",\n    \"created_at\": 1698771000,\n    \"tags\": [\n        [\"d\", \"order_marketplace_001:variation:001\"],\n        [\"t\", \"variation-request\"],\n        [\"alt\", \"Variation request: addition to order_marketplace_001\"],\n        [\"variation_type\", \"addition\"],\n        [\"p\", \"<provider-hex-pubkey>\"],\n        [\"e\", \"<original-agreement-event-id>\", \"wss://relay.example.com\"],\n        [\"amount\", \"15000\"],\n        [\"currency\", \"SAT\"],\n        [\"schedule_impact_days\", \"3\"]\n    ],\n    \"content\": \"Adding express shipping to the order. Original order was standard delivery. Need it by Friday instead of next Wednesday.\",\n    \"id\": \"<32-bytes lowercase hex>\",\n    \"sig\": \"<64-bytes lowercase hex>\"\n}\n```\n\nTags:\n\n* `d` (REQUIRED): Format `<context_id>:variation:<sequence>`. Addressable event identifier.\n* `t` (REQUIRED): Protocol family marker. MUST be `\"variation-request\"`.\n* `variation_type` (REQUIRED): Nature of the change. One of `\"addition\"`, `\"removal\"`, `\"substitution\"`, `\"modification\"`, or `\"schedule_change\"`.\n* `p` (RECOMMENDED): Other party's hex pubkey.\n* `e` (RECOMMENDED): Event ID of the original scope or agreement event.\n* `amount` (OPTIONAL): Estimated cost impact (delta from original, not new total). Positive for increase, negative for decrease. In smallest currency unit (pence for GBP, cents for USD, satoshis for SAT).\n* `currency` (OPTIONAL): Currency code (e.g. `GBP`, `USD`, `EUR`, `SAT`).\n* `schedule_impact_days` (OPTIONAL): Estimated schedule impact in days.\n* `ref` (OPTIONAL): External reference (variation order number, change request ID).\n\n**Content:** Plain text or NIP-44 encrypted JSON describing the requested change in detail.\n\n### Variation Types\n\n| Type | Description |\n|------|-------------|\n| `addition` | New deliverable, feature, or line item added to the original scope |\n| `removal` | Existing deliverable removed from scope (may reduce price) |\n| `substitution` | One deliverable replaced with another of comparable purpose |\n| `modification` | Existing deliverable changed in specification, quantity, or quality |\n| `schedule_change` | Timeline or deadline adjustment with no change to deliverables |\n\n### REQ Filters\n\nClients can subscribe to variation requests using standard NIP-01 filters:\n\nAll variation requests for a specific agreement:\n\n```json\n{\"kinds\": [30579], \"#e\": [\"<original-agreement-event-id>\"]}\n```\n\nAll variation requests from a specific party:\n\n```json\n{\"kinds\": [30579], \"authors\": [\"<requester-pubkey>\"]}\n```\n\nAll variation requests addressed to a specific provider:\n\n```json\n{\"kinds\": [30579], \"#p\": [\"<provider-pubkey>\"]}\n```\n\nA specific variation request by d-tag:\n\n```json\n{\"kinds\": [30579], \"#d\": [\"order_marketplace_001:variation:001\"]}\n```\n\n> **Note:** Tags such as `variation_type`, `amount`, `currency`, and `schedule_impact_days` are multi-letter tags. Standard relays index only single-letter tags (`d`, `e`, `p`, `t`). Discovery SHOULD use `kinds`, `authors`, `#e`, `#p`, and `#d` filters as shown above. Multi-letter tag values are available after fetching the event and SHOULD be applied as client-side filters.\n\n---\n\n## Composing with NIP-QUOTE\n\nWhen a variation has a price impact, the provider publishes a Quote (kind 30530) referencing the Variation Request. The Quote's `amount` is the price delta, and `breakdown` tags detail what changed.\n\n### Example: Quoting a Variation\n\nThe requester published a Variation Request (kind 30579) asking to add express shipping. The provider responds with a Quote:\n\n```json\n{\n    \"kind\": 30530,\n    \"pubkey\": \"<provider-hex-pubkey>\",\n    \"created_at\": 1698772000,\n    \"tags\": [\n        [\"d\", \"order_marketplace_001:variation:001:quote\"],\n        [\"alt\", \"Quote for variation: express shipping upgrade, 18000 SAT\"],\n        [\"e\", \"<variation-request-event-id>\", \"wss://relay.example.com\"],\n        [\"p\", \"<requester-hex-pubkey>\"],\n        [\"amount\", \"18000\"],\n        [\"currency\", \"SAT\"],\n        [\"breakdown\", \"express_shipping_upgrade\", \"15000\", \"SAT\"],\n        [\"breakdown\", \"repackaging_fee\", \"3000\", \"SAT\"],\n        [\"rate_unit\", \"flat\"],\n        [\"valid_until\", \"1699376800\"],\n        [\"payment_method\", \"lightning\"],\n        [\"payment_method\", \"cashu\"]\n    ],\n    \"content\": \"Express shipping upgrade: 18,000 sats. Includes repackaging for expedited courier. No schedule impact; can dispatch today if approved by 14:00.\",\n    \"id\": \"<32-bytes lowercase hex>\",\n    \"sig\": \"<64-bytes lowercase hex>\"\n}\n```\n\nKey points:\n\n* The `e` tag references the Variation Request (kind 30579), linking the quote to the specific change proposal.\n* The `amount` is the price **delta**, not the new total. The original agreement's price remains unchanged until the variation is approved.\n* `breakdown` tags itemise the cost of the change, making the delta auditable.\n* `valid_until` sets a deadline. Expired quotes MUST NOT be approved.\n* All standard NIP-QUOTE tags (`payment_method`, `rate_unit`, `mint_url`, etc.) are available.\n\nIf the variation also changes the payment structure (e.g. adding a new milestone), Payment Terms (kind 30531) MAY follow, referencing the Quote.\n\n---\n\n## Composing with NIP-APPROVAL\n\nVariation approval uses NIP-APPROVAL. A proposer (or system) creates an Approval Gate (kind 30570) referencing the Variation Request and optionally the Quote. The counterparty responds with an Approval Response (kind 30571).\n\n### Example: Approval Gate for a Variation\n\nAfter the provider quotes the express shipping upgrade, an Approval Gate is created for the requester to sign off:\n\n```json\n{\n    \"kind\": 30570,\n    \"pubkey\": \"<provider-hex-pubkey>\",\n    \"created_at\": 1698772500,\n    \"tags\": [\n        [\"d\", \"order_marketplace_001:variation:001:gate:approval\"],\n        [\"t\", \"approval-gate\"],\n        [\"alt\", \"Approval gate for variation: express shipping upgrade\"],\n        [\"gate_type\", \"approval\"],\n        [\"gate_authority\", \"<requester-hex-pubkey>\"],\n        [\"gate_status\", \"pending\"],\n        [\"e\", \"<variation-request-event-id>\", \"wss://relay.example.com\"],\n        [\"e\", \"<variation-quote-event-id>\", \"wss://relay.example.com\"],\n        [\"expiration\", \"1699376800\"]\n    ],\n    \"content\": \"Variation approval required: express shipping upgrade, 18,000 SAT delta. See referenced Quote for breakdown.\",\n    \"id\": \"<32-bytes lowercase hex>\",\n    \"sig\": \"<64-bytes lowercase hex>\"\n}\n```\n\n### Example: Approval Response\n\nThe requester approves the variation:\n\n```json\n{\n    \"kind\": 30571,\n    \"pubkey\": \"<requester-hex-pubkey>\",\n    \"created_at\": 1698773000,\n    \"tags\": [\n        [\"d\", \"order_marketplace_001:variation:001:gate:approval:response:<requester-hex-pubkey>\"],\n        [\"t\", \"approval-response\"],\n        [\"alt\", \"Approval response: approved variation for express shipping upgrade\"],\n        [\"e\", \"<approval-gate-event-id>\", \"wss://relay.example.com\"],\n        [\"decision\", \"approved\"],\n        [\"p\", \"<provider-hex-pubkey>\"]\n    ],\n    \"content\": \"Approved. Please dispatch with express shipping today.\",\n    \"id\": \"<32-bytes lowercase hex>\",\n    \"sig\": \"<64-bytes lowercase hex>\"\n}\n```\n\nKey points:\n\n* The Approval Gate references both the Variation Request and the Quote via `e` tags, creating a verifiable chain.\n* `gate_authority` names the party whose sign-off is required. For variations requiring mutual agreement, list both parties.\n* The Approval Response's `decision` tag uses the standard NIP-APPROVAL values: `\"approved\"`, `\"rejected\"`, or `\"revise\"`.\n* Rejection or revision request works identically to any other NIP-APPROVAL flow. If the requester rejects, the variation is abandoned. If they request revision, the provider updates the Quote.\n* The `expiration` tag on the gate SHOULD match the Quote's `valid_until` to avoid approving an expired price.\n\n---\n\n## Protocol Flow\n\n\n![Variation Flow](https://raw.githubusercontent.com/forgesworn/nip-drafts/main/images/variation-1.png)\n\n```mermaid\nsequenceDiagram\n    actor R as Requester\n    actor P as Provider\n\n    R->>P: kind:30579 Variation Request\n    Note right of R: variation_type, estimated amount,<br/>schedule impact\n\n    P->>R: kind:30530 Quote (NIP-QUOTE)\n    Note right of P: Price delta with breakdown,<br/>valid_until deadline\n\n    P->>R: kind:30570 Approval Gate (NIP-APPROVAL)\n    Note right of P: References Variation Request<br/>and Quote via e tags\n\n    R->>P: kind:30571 Approval Response (NIP-APPROVAL)\n    Note left of R: decision: approved\n\n    Note over R,P: Optional: kind:30532 supplementary Lock<br/>(NIP-ESCROW) for the price delta\n```\n\n1. **Request:** Either party publishes `kind:30579` describing the desired change, its type, and optionally an estimated cost impact.\n2. **Quote (optional):** If the variation has a price impact, the provider publishes a NIP-QUOTE Quote (kind 30530) referencing the Variation Request, with the confirmed cost delta and breakdown.\n3. **Approval Gate:** A NIP-APPROVAL Approval Gate (kind 30570) is created, referencing the Variation Request and (if present) the Quote. The `gate_authority` identifies who must sign off.\n4. **Approval Response:** The counterparty publishes a NIP-APPROVAL Approval Response (kind 30571) with their decision.\n5. **Execution:** If approved, the consuming application updates its internal state to reflect the new scope, price, and timeline. A supplementary NIP-ESCROW Lock (kind 30532) MAY be published to cover the price delta.\n\n### Variations Without Price Impact\n\nNot all variations require a Quote. A `schedule_change` that moves the deadline by two days, or a `substitution` at equal value, may need only an Approval Gate and Response. The Quote step is optional; the protocol flow adapts:\n\n```\nVariation Request → Approval Gate → Approval Response\n```\n\n---\n\n## Example Applications\n\n### Marketplace Order Modifications\n\nWhen a buyer wants to modify an accepted marketplace order (NIP-15), the variation flow provides a structured negotiation. The buyer requests a change, the seller quotes the impact via NIP-QUOTE, and the buyer approves via NIP-APPROVAL before any changes take effect.\n\n### Freelance Scope Changes\n\nFreelance projects frequently encounter scope creep. NIP-VARIATION provides a formal mechanism for managing mid-project changes. When a client wants additional work, the freelancer quotes the cost and timeline impact, and the client explicitly approves. This prevents disputes about what was agreed and what was extra.\n\n### Subscription & Service Plan Changes\n\nSubscription services on Nostr can use variations to manage plan changes. The `variation_type: substitution` models a plan swap, while `addition` models add-on features. The Quote captures the price difference; the Approval Gate records the customer's consent.\n\n### Event & Booking Modifications\n\nWhen plans change after a booking has been confirmed, the variation flow ensures both parties agree to the revised terms and pricing before changes are made.\n\n## Security Considerations\n\n* **Reference chain integrity.** The full variation flow creates a verifiable chain: Variation Request -> Quote -> Approval Gate -> Approval Response. Clients MUST verify that `e` tag references are valid and form a consistent chain.\n* **Quote expiry.** Variation quotes with a `valid_until` tag SHOULD be considered expired after the deadline. Clients MUST NOT create Approval Gates referencing expired Quotes.\n* **Decision finality.** Once an Approval Response (kind 30571) is published with `approved` or `rejected`, the decision SHOULD be treated as final. Applications SHOULD warn if a gate is modified after a final decision has been recorded.\n* **Amount validation.** Clients SHOULD verify that the Quote's `amount` is reasonable relative to the Variation Request's estimated amount. Large discrepancies SHOULD be flagged to the requester.\n* **Content encryption.** When variation details are commercially sensitive (pricing strategy, proprietary specifications), the `content` field SHOULD be NIP-44 encrypted to the relevant parties.\n* **Authorisation.** Only the original parties to the agreement SHOULD be able to publish variation events. Clients SHOULD verify that variation event authors are participants in the original agreement.\n\n## Privacy\n\nVariation Requests are public by default. When scope changes are commercially sensitive, implementations MAY deliver events via NIP-59 gift wrap. This is an application-level decision, not a protocol requirement.\n\n### Metadata minimisation\n\nImplementations SHOULD include only the tags marked REQUIRED or RECOMMENDED. Optional tags (`amount`, `currency`, `schedule_impact_days`, `ref`) increase the metadata surface; omit them unless the application specifically needs them.\n\n## Test Vectors\n\nAll examples use timestamp `1709740800` (2024-03-06T12:00:00Z) and placeholder hex pubkeys.\n\n### Kind 30579 -- Variation Request\n\n```json\n{\n    \"kind\": 30579,\n    \"pubkey\": \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\",\n    \"created_at\": 1709740800,\n    \"tags\": [\n        [\"d\", \"project_alpha:variation:003\"],\n        [\"t\", \"variation-request\"],\n        [\"alt\", \"Variation request: addition to project_alpha\"],\n        [\"variation_type\", \"addition\"],\n        [\"p\", \"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\"],\n        [\"e\", \"dddd4444eeee5555ffff6666aaaa1111bbbb2222cccc3333dddd4444eeee5555\", \"wss://relay.example.com\"],\n        [\"amount\", \"25000\"],\n        [\"currency\", \"SAT\"],\n        [\"schedule_impact_days\", \"5\"],\n        [\"ref\", \"VO-2024-003\"]\n    ],\n    \"content\": \"Adding dark mode support to the web dashboard. Original scope covered light theme only. Estimated 5 additional days for CSS rework and testing.\",\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-40](https://github.com/nostr-protocol/nips/blob/master/40.md): Expiration timestamps (quote validity, gate deadlines)\n* [NIP-44](https://github.com/nostr-protocol/nips/blob/master/44.md): Versioned encrypted payloads (sensitive variation details)\n* NIP-QUOTE: Structured pricing (quoting the cost of a variation)\n* NIP-APPROVAL: Multi-party approval gates (approving or rejecting a variation)\n\n## Reference Implementations\n\nNo public reference implementation exists yet. Implementors SHOULD refer to the kind definitions above.\n\nA minimal implementation requires:\n\n1. A Nostr client that supports addressable event publishing.\n2. Reference chain tracking: linking Variation Requests to Quotes (NIP-QUOTE) and Approval Gates (NIP-APPROVAL) via `e` tags.\n3. State management to update the original agreement's effective scope and price when a variation is approved.\n\n## Standalone Usage\n\nNIP-VARIATION is designed for standalone use. Any Nostr application where agreed scope needs to change can use kind 30579 without adopting NIP-QUOTE, NIP-APPROVAL, or NIP-ESCROW. A simple two-party chat application could use Variation Requests as structured \"change proposals\" with approval handled informally. As needs grow, the NIP-QUOTE and NIP-APPROVAL composition patterns provide structured pricing and formal sign-off without changing the Variation Request format.","sig":"9404af25941ba8659ad98d00fb55840f8fe229583d2fee20782c07d975be9dbc9b1eb9095d1e6b4559205dde0cbb341548fb335c286db421b66d1525c17dc1c6"}