12<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width, initial-scale=1">6<title>NIP-90 - Data Vending Machine — Nostr Instruction Manual</title>7<meta name="description" content="NIP-90 (deprecated): the Data Vending Machine. Job request kinds 5000-5999, job results 6000-6999, kind 7000 feedback, and the payment flow. Complete manual page.">8<link rel="preload" href="../assets/fonts/michroma-400-latin.woff2" as="font" type="font/woff2" crossorigin>9<link rel="preload" href="../assets/fonts/exo2-var-latin.woff2" as="font" type="font/woff2" crossorigin>10<link rel="preload" href="../assets/fonts/sairacondensed-600-latin.woff2" as="font" type="font/woff2" crossorigin>11<link rel="preload" href="../assets/fonts/sairacondensed-700-latin.woff2" as="font" type="font/woff2" crossorigin>12<link rel="preload" href="../assets/fonts/sairacondensed-500-latin.woff2" as="font" type="font/woff2" crossorigin>13<link rel="preload" href="../assets/fonts/sharetechmono-400-latin.woff2" as="font" type="font/woff2" crossorigin>14<link rel="preload" href="../assets/fonts/exo2-400i-latin.woff2" as="font" type="font/woff2" crossorigin>15<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml">16<link rel="stylesheet" href="../assets/manual.css">17</head>18<body>1920<svg width="0" height="0" style="position:absolute">21 <defs>22 <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">23 <path d="M1,1 L8,4.5 L1,8 Z" fill="#f26a00"/>24 </marker>25 <marker id="arrb" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">26 <path d="M1,1 L8,4.5 L1,8 Z" fill="#2e5f9e"/>27 </marker>28 </defs>29</svg>3031<div class="page">32 <span class="staple s1"></span><span class="staple s2"></span>3334 <header class="band">35 <a class="logo" href="../index.html">NOSTR<b>▸</b>PROTOCOL MANUAL</a>36 <span class="booklet-note">Chapter 90 - Marketplace</span>37 </header>38 <nav class="tabs">39 <a href="../index.html">Contents</a>40 <a href="#overview" class="on">Overview</a>41 <a href="#spec">Spec</a>42 <a href="#examples">Examples</a>43 <a href="#history">History</a>44 </nav>4546 <div class="chapter">47 <div class="nipno" data-n="90">90</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 90</div>50 <h1>Data Vending Machine</h1>51 <p class="sub">Money in, data out: customers publish paid compute jobs, and service providers compete to return the results.</p>52 </div>53 <div class="stamp">Deprecated</div>54 </div>5556 <main class="spread">57 <div class="main">5859 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>6061 <div class="box danger">62 <span class="tag">Deprecated</span>63 <p>The source repository marks this NIP <strong>unrecommended</strong>. The stated reason: "this got totally out of control, prefer use-case-specific microstandards." No single NIP replaces it. New designs should define a small, dedicated event kind for each use case instead of this generic job framework. This chapter documents the full spec for readers who maintain existing DVM software.</p>64 </div>6566 <p>A <strong>Data Vending Machine</strong> (DVM) turns Nostr into a marketplace for on-demand computation. A user wants some data processed — speech-to-text, translation, summarization. The user does not care <em>who</em> does the work. The user cares only about the output and the price.</p>67 <p>This NIP defines two actors. A <strong>customer</strong> is an npub that requests a job. A <strong>service provider</strong> is an npub that fulfills jobs. The customer publishes a job request event. Any service provider can see it, work on it, and publish a result. Providers compete to deliver the best output.</p>68 <p>This is not a 1:1 marketplace. The customer announces a desired output and a willingness to pay. The customer does not hire one provider. Several providers may answer the same request. Payment travels over Lightning: a bolt11 invoice or a zap.</p>6970 <figure class="diagram">71 <div class="frame">72 <svg viewBox="0 0 560 200" role="img" aria-label="A customer publishes a job request to a relay; three competing service providers read it and publish results back">73 <rect class="d-actor" x="10" y="75" width="110" height="50" rx="8"/>74 <text class="d-actor-label" x="65" y="104" text-anchor="middle">Customer</text>75 <rect class="d-actor" x="225" y="75" width="110" height="50" rx="8"/>76 <text class="d-actor-label" x="280" y="104" text-anchor="middle">Relay</text>77 <rect class="d-actor" x="440" y="14" width="110" height="42" rx="8"/>78 <text class="d-actor-label" x="495" y="40" text-anchor="middle">Provider 1</text>79 <rect class="d-actor" x="440" y="79" width="110" height="42" rx="8"/>80 <text class="d-actor-label" x="495" y="105" text-anchor="middle">Provider 2</text>81 <rect class="d-actor" x="440" y="144" width="110" height="42" rx="8"/>82 <text class="d-actor-label" x="495" y="170" text-anchor="middle">Provider 3</text>83 <path class="d-msg d-flow" d="M122,100 L222,100"/>84 <text class="d-label" x="172" y="92" text-anchor="middle">kind:5xxx</text>85 <path class="d-msg blue d-flow" d="M337,88 C380,72 395,52 438,40"/>86 <path class="d-msg blue d-flow" d="M337,100 L437,100"/>87 <path class="d-msg blue d-flow" d="M337,112 C380,128 395,148 438,160"/>88 <text class="d-label" x="388" y="130" text-anchor="middle">compete</text>89 <circle r="4" fill="#f26a00">90 <animateMotion dur="2.6s" repeatCount="indefinite" path="M122,100 L222,100"/>91 </circle>92 <circle r="4" fill="#2e5f9e">93 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M337,100 L437,100"/>94 </circle>95 </svg>96 </div>97 <figcaption>Fig. 90-1 — <b>The vending machine market.</b> One request goes out. Many providers may answer. The customer pays for the result it likes.</figcaption>98 </figure>99100 <h2 class="bar" id="spec"><span class="num">2</span> Reserved Kinds</h2>101 <p>This NIP reserves the kind range <code>5000-7000</code> for data vending machine use. The range splits into three roles:</p>102103 <div class="tscroll"><table class="ref">104 <caption>DVM kind ranges</caption>105 <tr><th>Kind</th><th>Description</th></tr>106 <tr><td class="btn">5000-5999</td><td>Job request kinds. Published by customers.</td></tr>107 <tr><td class="btn">6000-6999</td><td>Job results. Published by service providers.</td></tr>108 <tr><td class="btn">7000</td><td>Job feedback. Published by service providers.</td></tr>109 </table></div>110111 <p>A job result always uses a kind number that is exactly <code>1000</code> higher than its job request kind. A request with <code>kind:5001</code> gets a result with <code>kind:6001</code>. The individual job request types are not defined here. They live in a separate registry: the <code>nostr-protocol/data-vending-machines</code> repository on GitHub.</p>112113 <div class="box tech">114 <span class="tag">Tech Note</span>115 <p>The job-type registry sits outside the NIPs repository, so this spec is incomplete on its own. Also, the request example includes a <code>["t", "bitcoin"]</code> tag, but the tag list in the spec never defines <code>t</code>. Read it as a topic label borrowed from common Nostr practice; the NIP-89 appendix example uses it the same way.</p>116 </div>117118 <h2 class="bar" id="request"><span class="num">3</span> Job Request (kind 5000-5999)</h2>119 <p>A customer publishes a job request to signal interest in the result of some compute. The event looks like this:</p>120121 <div class="crt">122 <div class="titlebar">Wire format - job request</div>123<pre>{124 <span class="k">"kind"</span>: <span class="c"><5xxx - kind in the 5000-5999 range></span>,125 <span class="k">"content"</span>: <span class="s">""</span>,126 <span class="k">"tags"</span>: [127 [<span class="s">"i"</span>, <span class="c"><data></span>, <span class="c"><input-type></span>, <span class="c"><relay></span>, <span class="c"><marker></span>],128 [<span class="s">"output"</span>, <span class="c"><mime-type></span>],129 [<span class="s">"param"</span>, <span class="c"><key></span>, <span class="c"><value></span>],130 [<span class="s">"bid"</span>, <span class="c"><msat-amount></span>],131 [<span class="s">"relays"</span>, <span class="s">"wss://..."</span>],132 [<span class="s">"p"</span>, <span class="c"><provider pubkey></span>],133 [<span class="s">"t"</span>, <span class="s">"bitcoin"</span>]134 ]135 <span class="c">// other fields...</span>136}</pre>137 </div>138139 <p>All tags are optional. A request may carry zero or more <code>i</code> inputs.</p>140141 <div class="tscroll"><table class="ref">142 <caption>Job request tags</caption>143 <tr><th>Tag</th><th>Meaning</th></tr>144 <tr><td class="btn">i</td><td>One input for the job: <code>["i", <data>, <input-type>, <relay>, <marker>]</code>. See the input-type table below. The <code>marker</code> is optional; it says how the provider should use this input within the job.</td></tr>145 <tr><td class="btn">output</td><td>Expected output format as a MIME type. Each job request kind defines this more precisely.</td></tr>146 <tr><td class="btn">param</td><td>An optional job parameter as a key (first argument) and value (second argument), for example <code>["param", "lang", "es"]</code>. Each job request kind defines its parameters more precisely.</td></tr>147 <tr><td class="btn">bid</td><td>The maximum amount, in millisats, that the customer is willing to pay.</td></tr>148 <tr><td class="btn">relays</td><td>The relays where service providers should publish their responses.</td></tr>149 <tr><td class="btn">p</td><td>A service provider the customer is interested in. Other providers might still choose to process the job.</td></tr>150 </table></div>151152 <div class="tscroll"><table class="ref">153 <caption>Input types (2nd element of the i tag)</caption>154 <tr><th>Type</th><th>Meaning of <data></th></tr>155 <tr><td class="btn">url</td><td>A URL. The provider fetches it to get the data to process.</td></tr>156 <tr><td class="btn">event</td><td>A Nostr event ID. The <code>relay</code> element names the relay where the event was published.</td></tr>157 <tr><td class="btn">job</td><td>The event ID of a previous job. The provider builds on that job's output. The provider decides which output to use — it may wait for a signal from the customer or for a payment. The <code>relay</code> element names the relay where the job was published.</td></tr>158 <tr><td class="btn">text</td><td>The literal input value. No resolution is needed.</td></tr>159 </table></div>160 <p>For the <code>url</code> and <code>text</code> input types, the <code>relay</code> element is optional or an empty string.</p>161162 <h3>Encrypted params</h3>163 <p>A customer can keep the job inputs secret. Take the <code>i</code> and <code>param</code> tags out of the tags array. Encrypt them with <a href="04.html">NIP-04</a>, using the customer's private key and the provider's public key for the shared secret. Put the ciphertext in the <code>content</code> field. Add an <code>["encrypted"]</code> tag as a marker, and keep a <code>p</code> tag with the provider's pubkey. Plaintext before encryption:</p>164165 <div class="crt">166 <div class="titlebar">Private tags - before encryption</div>167<pre>[168 [<span class="s">"i"</span>, <span class="s">"what is the capital of France? "</span>, <span class="s">"text"</span>],169 [<span class="s">"param"</span>, <span class="s">"model"</span>, <span class="s">"LLaMA-2"</span>],170 [<span class="s">"param"</span>, <span class="s">"max_tokens"</span>, <span class="s">"512"</span>],171 [<span class="s">"param"</span>, <span class="s">"temperature"</span>, <span class="s">"0.5"</span>],172 [<span class="s">"param"</span>, <span class="s">"top-k"</span>, <span class="s">"50"</span>],173 [<span class="s">"param"</span>, <span class="s">"top-p"</span>, <span class="s">"0.7"</span>],174 [<span class="s">"param"</span>, <span class="s">"frequency_penalty"</span>, <span class="s">"1"</span>]175]</pre>176 </div>177178 <div class="crt">179 <div class="titlebar">Encrypted job request - on the wire</div>180<pre>{181 <span class="k">"content"</span>: <span class="s">"BE2Y4xvS6HIY7TozIgbEl3sAHkdZoXyLRRkZv4fLPh3R7LtviLKAJM5qpkC7D6VtMbgIt4iNcMpLtpo..."</span>,182 <span class="k">"tags"</span>: [183 [<span class="s">"p"</span>, <span class="s">"04f74530a6ede6b24731b976b8e78fb449ea61f40ff10e3d869a3030c4edc91f"</span>],184 [<span class="s">"encrypted"</span>]185 ]186 <span class="c">// other fields...</span>187}</pre>188 </div>189190 <div class="box tech">191 <span class="tag">Tech Note</span>192 <p>Two issues here. First, the spec mandates <a href="04.html">NIP-04</a> encryption, and NIP-04 is itself deprecated in favor of <a href="44.html">NIP-44</a>. Second, the spec says "all tags are optional" for requests, yet the encrypted flow says the <code>p</code> tag "should be present" — an unresolved soft contradiction. In practice an encrypted request without <code>p</code> cannot be decrypted by anyone.</p>193 </div>194195 <h2 class="bar" id="result"><span class="num">4</span> Job Result (kind 6000-6999)</h2>196 <p>A service provider publishes the job output as a result event. The provider tags the original job request event ID and the customer's pubkey. The output payload goes in <code>content</code>.</p>197198 <div class="crt">199 <div class="titlebar">Wire format - job result</div>200<pre>{201 <span class="k">"pubkey"</span>: <span class="c"><service-provider pubkey></span>,202 <span class="k">"content"</span>: <span class="c"><payload></span>,203 <span class="k">"kind"</span>: <span class="c"><6xxx - request kind + 1000></span>,204 <span class="k">"tags"</span>: [205 [<span class="s">"request"</span>, <span class="c"><job-request></span>],206 [<span class="s">"e"</span>, <span class="c"><job-request-id></span>, <span class="c"><relay-hint></span>],207 [<span class="s">"i"</span>, <span class="c"><input-data></span>],208 [<span class="s">"p"</span>, <span class="c"><customer's pubkey></span>],209 [<span class="s">"amount"</span>, <span class="c"><requested-payment-amount></span>, <span class="c"><optional-bolt11></span>]210 ]211 <span class="c">// other fields...</span>212}</pre>213 </div>214215 <div class="tscroll"><table class="ref">216 <caption>Job result tags</caption>217 <tr><th>Tag</th><th>Meaning</th></tr>218 <tr><td class="btn">request</td><td>The whole job request event as stringified JSON.</td></tr>219 <tr><td class="btn">e</td><td>The job request event ID, with an optional relay hint.</td></tr>220 <tr><td class="btn">i</td><td>The original input(s) from the request, repeated.</td></tr>221 <tr><td class="btn">p</td><td>The customer's pubkey.</td></tr>222 <tr><td class="btn">amount</td><td>The millisats the provider requests as payment. An optional third value is a bolt11 invoice.</td></tr>223 </table></div>224225 <h3>Encrypted output</h3>226 <p>If the request had encrypted params, encrypt the output too. Put the ciphertext in <code>content</code>. Add an <code>["encrypted"]</code> tag. Do not include an <code>i</code> tag with the input data in clear text — that would leak the secret input.</p>227228 <div class="crt">229 <div class="titlebar">Wire format - encrypted job result</div>230<pre>{231 <span class="k">"pubkey"</span>: <span class="c"><service-provider pubkey></span>,232 <span class="k">"content"</span>: <span class="c"><encrypted payload></span>,233 <span class="k">"kind"</span>: <span class="c"><6xxx></span>,234 <span class="k">"tags"</span>: [235 [<span class="s">"request"</span>, <span class="c"><job-request></span>],236 [<span class="s">"e"</span>, <span class="c"><job-request-id></span>, <span class="c"><relay-hint></span>],237 [<span class="s">"p"</span>, <span class="c"><customer's pubkey></span>],238 [<span class="s">"amount"</span>, <span class="c"><requested-payment-amount></span>, <span class="c"><optional-bolt11></span>],239 [<span class="s">"encrypted"</span>]240 ]241 <span class="c">// other fields...</span>242}</pre>243 </div>244245 <h2 class="bar" id="feedback"><span class="num">5</span> Job Feedback (kind 7000)</h2>246 <p>A service provider can report progress on a job back to the customer with a <code>kind:7000</code> event. The <code>content</code> field is empty, or it carries a job result — for example a sample of partial results, as described in the Job Result section. If the request required encrypted input, encrypt the feedback <code>content</code> the same way, keyed by the <code>p</code> tag.</p>247248 <div class="crt">249 <div class="titlebar">Wire format - job feedback</div>250<pre>{251 <span class="k">"kind"</span>: <span class="s">7000</span>,252 <span class="k">"content"</span>: <span class="c"><empty-or-payload></span>,253 <span class="k">"tags"</span>: [254 [<span class="s">"status"</span>, <span class="c"><status></span>, <span class="c"><extra-info></span>],255 [<span class="s">"amount"</span>, <span class="c"><requested-payment-amount></span>, <span class="c"><bolt11></span>],256 [<span class="s">"e"</span>, <span class="c"><job-request-id></span>, <span class="c"><relay-hint></span>],257 [<span class="s">"p"</span>, <span class="c"><customer's pubkey></span>]258 ]259 <span class="c">// other fields...</span>260}</pre>261 </div>262263 <p>The <code>amount</code> tag works exactly as in the job result. The <code>status</code> tag should name one of five defined states. The provider may add extra human-readable information as the third element.</p>264265 <div class="tscroll"><table class="ref">266 <caption>Job feedback status values</caption>267 <tr><th>Status</th><th>Description</th></tr>268 <tr><td class="btn">payment-required</td><td>The provider requires payment before continuing.</td></tr>269 <tr><td class="btn">processing</td><td>The provider is processing the job.</td></tr>270 <tr><td class="btn">error</td><td>The provider was unable to process the job.</td></tr>271 <tr><td class="btn">success</td><td>The provider successfully processed the job.</td></tr>272 <tr><td class="btn">partial</td><td>The provider partially processed the job. The <code>content</code> might include a sample of the partial results.</td></tr>273 </table></div>274275 <h2 class="bar" id="flow"><span class="num">6</span> Protocol Flow and Payment</h2>276 <p>The full lifecycle has four steps:</p>277 <ol>278 <li>The customer publishes a job request, for example a <code>kind:5000</code> speech-to-text job.</li>279 <li>Service providers may publish <code>kind:7000</code> feedback events: <code>payment-required</code>, <code>processing</code>, <code>error</code>, and so on.</li>280 <li>On completion, the provider publishes the result as a <code>kind:6xxx</code> job result event.</li>281 <li>At any point, if an <code>amount</code> is pending as instructed by the provider, the customer pays the included bolt11 invoice or zaps the provider's event.</li>282 </ol>283 <p>An <code>amount</code> tag on a feedback or result event is only a <em>suggestion</em> to pay. One signal is strict: a provider must send a <code>payment-required</code> feedback event when payment is a hard requirement. After that event, the provider performs no further work until the customer pays. The customer can always pay the bolt11 invoice or zap (<a href="57.html">NIP-57</a>) the event that requests payment. A provider that includes a bolt11 invoice should monitor for both payment paths.</p>284285 <figure class="diagram">286 <div class="frame">287 <svg viewBox="0 0 560 320" role="img" aria-label="Sequence diagram: customer publishes a job request, provider replies with payment-required feedback, customer pays, provider sends processing feedback and then the job result">288 <line class="d-wire" x1="110" y1="40" x2="110" y2="305" stroke-dasharray="3 4"/>289 <line class="d-wire" x1="450" y1="40" x2="450" y2="305" stroke-dasharray="3 4"/>290 <rect class="d-actor" x="55" y="8" width="110" height="30" rx="6"/>291 <text class="d-actor-label" x="110" y="28" text-anchor="middle">Customer</text>292 <rect class="d-actor" x="395" y="8" width="110" height="30" rx="6"/>293 <text class="d-actor-label" x="450" y="28" text-anchor="middle">Provider</text>294 <path class="d-msg" d="M110,62 L445,62"/>295 <text class="d-label" x="280" y="55" text-anchor="middle">kind:5000 job request ("i", "bid")</text>296 <path class="d-msg blue" d="M450,105 L115,105"/>297 <text class="d-label" x="280" y="98" text-anchor="middle">kind:7000 ["status","payment-required"] + amount</text>298 <path class="d-msg d-flow" d="M110,148 L445,148"/>299 <text class="d-label" x="280" y="141" text-anchor="middle">pay bolt11 - or zap the event</text>300 <path class="d-msg blue" d="M450,191 L115,191"/>301 <text class="d-label" x="280" y="184" text-anchor="middle">kind:7000 ["status","processing"]</text>302 <path class="d-msg blue" d="M450,234 L115,234"/>303 <text class="d-label" x="280" y="227" text-anchor="middle">kind:6000 job result</text>304 <text class="d-note" x="280" y="272" text-anchor="middle">Order is flexible. Some providers deliver first and ask payment later.</text>305 <circle r="4" fill="#f26a00">306 <animateMotion dur="2.6s" repeatCount="indefinite" path="M110,148 L445,148"/>307 </circle>308 </svg>309 </div>310 <figcaption>Fig. 90-2 — <b>One possible payment flow.</b> Feedback events narrate the job. Only <code>payment-required</code> has a strict meaning.</figcaption>311 </figure>312313 <p>The flow is deliberately ambiguous. Each provider models its own risk. Some providers demand <code>payment-required</code> first, before any <code>processing</code> event or any result. Some serve a <code>partial</code> sample and demand payment for the rest. Some judge an npub's past behavior, deliver the full result first, and request payment after — the best possible UX. This NIP does not define how a vending machine runs its business.</p>314315 <h3>Cancellation</h3>316 <p>A customer can cancel a job request. Publish a <code>kind:5</code> delete request event (<a href="09.html">NIP-09</a>) that tags the job request event.</p>317318 <h2 class="bar" id="chaining"><span class="num">7</span> Appendix 1: Job Chaining</h2>319 <p>A customer may request several jobs as a chain. The output of one job is the input of the next. Example: podcast transcription, then summarization of the transcript. To chain, set the input of the second request to the first job's event ID with the <code>job</code> input type.</p>320321 <figure class="diagram">322 <div class="frame">323 <svg viewBox="0 0 560 130" role="img" aria-label="Job chain: a transcription request produces a result, and a summarization request uses that result as its job-type input">324 <rect class="d-actor" x="10" y="40" width="120" height="50" rx="8"/>325 <text class="d-actor-label" x="70" y="62" text-anchor="middle">Request A</text>326 <text class="d-note" x="70" y="79" text-anchor="middle">kind:5000 transcribe</text>327 <rect class="d-actor" x="180" y="40" width="110" height="50" rx="8"/>328 <text class="d-actor-label" x="235" y="62" text-anchor="middle">Result A</text>329 <text class="d-note" x="235" y="79" text-anchor="middle">kind:6000</text>330 <rect class="d-actor" x="340" y="40" width="120" height="50" rx="8"/>331 <text class="d-actor-label" x="400" y="62" text-anchor="middle">Request B</text>332 <text class="d-note" x="400" y="79" text-anchor="middle">i = ["job", A-id]</text>333 <rect class="d-actor" x="500" y="40" width="50" height="50" rx="8"/>334 <text class="d-actor-label" x="525" y="70" text-anchor="middle">B...</text>335 <path class="d-msg d-flow" d="M132,65 L177,65"/>336 <path class="d-msg blue d-flow" d="M292,65 L337,65"/>337 <path class="d-msg d-flow" d="M462,65 L497,65"/>338 <text class="d-label" x="280" y="22" text-anchor="middle">output of job A feeds job B</text>339 </svg>340 </div>341 <figcaption>Fig. 90-3 — <b>Job chaining.</b> Request B names Result A as a <code>job</code>-type input. The chain can continue.</figcaption>342 </figure>343344 <p>A provider may start a chained job the moment it sees the prior job's result. In practice, most wait for a zap on the prior result first. This creates a risk: the provider of job #1 might delay publishing the zap event to gain an advantage. Providers must mitigate this risk themselves. A provider can also decide that job #1's provider is reliable enough, and not wait for an explicit zap to treat the job as accepted. This gives providers a high level of flexibility — sophisticated providers would take it anyway.</p>345346 <h2 class="bar" id="discovery"><span class="num">8</span> Appendix 2: Provider Discoverability</h2>347 <p>A service provider may advertise its supported job kinds with a <a href="89.html">NIP-89</a> handler announcement (<code>kind:31990</code>). Each supported job request kind goes in a <code>k</code> tag. Customers use <a href="89.html">NIP-89</a> to see which providers their follows use.</p>348349 <div class="crt">350 <div class="titlebar">NIP-89 announcement - DVM advertisement</div>351<pre>{352 <span class="k">"kind"</span>: <span class="s">31990</span>,353 <span class="k">"pubkey"</span>: <span class="c"><pubkey></span>,354 <span class="k">"content"</span>: <span class="s">"{\"name\": \"Translating DVM\",355 \"about\": \"I'm a DVM specialized in translating Bitcoin content.\"}"</span>,356 <span class="k">"tags"</span>: [357 [<span class="s">"k"</span>, <span class="s">"5005"</span>], <span class="c">// supported job request kind, e.g. translation</span>358 [<span class="s">"t"</span>, <span class="s">"bitcoin"</span>] <span class="c">// optional specialization topic</span>359 ]360 <span class="c">// other fields...</span>361}</pre>362 </div>363364 <h2 class="bar" id="examples"><span class="num">9</span> Worked Example</h2>365 <p>A customer wants a podcast episode transcribed. The transcript costs 5000 msats. The session below shows the events, in publish order, on the relay named in the <code>relays</code> tag. Orange lines are the customer's events. Blue lines are the provider's events.</p>366367 <div class="crt">368 <div class="titlebar">Event log - wss://relay.example.com</div>369<pre><span class="c">-- 1. customer publishes the job request --</span>370<span class="send">→ {"kind":5000, "pubkey":"aa31f7e2…", "content":"",371 "tags":[["i","https://cdn.example.com/ep42.mp3","url","",""],372 ["output","text/plain"],373 ["param","lang","en"],374 ["bid","10000"],375 ["relays","wss://relay.example.com"]], …}</span>376377<span class="c">-- 2. provider asks for payment before working --</span>378<span class="recv">← {"kind":7000, "pubkey":"04f74530…", "content":"",379 "tags":[["status","payment-required","5000 msats upfront"],380 ["amount","5000","lnbc50n1…"],381 ["e","<request-id>","wss://relay.example.com"],382 ["p","aa31f7e2…"]], …}</span>383384<span class="c">-- 3. customer pays the bolt11 invoice (off-Nostr, Lightning) --</span>385386<span class="c">-- 4. provider reports progress --</span>387<span class="recv">← {"kind":7000, "content":"",388 "tags":[["status","processing"],389 ["e","<request-id>","wss://relay.example.com"],390 ["p","aa31f7e2…"]], …}</span>391392<span class="c">-- 5. provider publishes the result (kind = 5000 + 1000) --</span>393<span class="recv">← {"kind":6000, "pubkey":"04f74530…",394 "content":"Welcome back to episode forty-two…",395 "tags":[["request","{\"kind\":5000,…}"],396 ["e","<request-id>","wss://relay.example.com"],397 ["i","https://cdn.example.com/ep42.mp3"],398 ["p","aa31f7e2…"],399 ["amount","5000"]], …}</span></pre>400 </div>401402 <div class="box hint">403 <span class="tag">Hint!</span>404 <p>Want the summary too? Publish a second request whose input is <code>["i", "<result-id>", "job", "wss://relay.example.com"]</code>. That is job chaining from §7 — the summarizer builds on the transcript event.</p>405 </div>406407 <h2 class="bar" id="history"><span class="num">10</span> Version History</h2>408 <p>NIP-90 grew fast in mid-2023, spawned an external kind registry and a whole DVM ecosystem, and was marked unrecommended in 2026. Notable changes, newest first:</p>409 <ul class="patchnotes">410 <li><span class="ver">2026</span><span class="when">2026-05</span>fiatjaf added the <code>unrecommended</code> tag and the warning: "this got totally out of control, prefer use-case-specific microstandards."</li>411 <li class="minor"><span class="ver">2024-25</span><span class="when">2024-2025</span>Typo, link, heading-level, and JSON formatting fixes; deletion events renamed to delete requests per <a href="09.html">NIP-09</a>.</li>412 <li><span class="ver">2023</span><span class="when">2023-10</span>Big refactor by Pablo Fernandez plus consistency changes by Semisol: the request/result/feedback structure settled into its final shape.</li>413 <li><span class="ver">2023</span><span class="when">2023-07</span>Renamed from <code>vending-machine.md</code> to <code>90.md</code> and merged into the NIPs repository. Each job type got its own request kind; results moved to request kind + 1000.</li>414 <li><span class="ver">2023</span><span class="when">2023-07</span>Optional bolt11 invoices added to the <code>amount</code> tag; feedback moved off kind 7 onto dedicated kind 7000.</li>415 <li><span class="ver">Origin</span><span class="when">2023-07</span>pablof7z drafted the first Data Vending Machine spec as <code>vending-machine.md</code>, with examples following two days later.</li>416 </ul>417418 <div class="credits">419 <h3 class="cardhead">Original Proposal - Credits</h3>420 <table>421 <tr><td>Author</td><td>pablof7z (Pablo Fernandez)</td></tr>422 <tr><td>First commit</td><td>2023-07-25 — “rename file” (drafted as <code>vending-machine.md</code> from 2023-07-03)</td></tr>423 <tr><td>Status</td><td>draft - unrecommended - optional — deprecated, kept for existing DVM software</td></tr>424 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/90.md">90.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/90.md">full change history</a></td></tr>425 </table>426 </div>427428 <h2 class="bar"><span class="num">11</span> See Also</h2>429 <ul>430 <li><a href="01.html">NIP-01</a> — the base event format, kinds, and tags this NIP builds on.</li>431 <li><a href="89.html">NIP-89</a> — handler announcements; how providers advertise supported job kinds.</li>432 <li><a href="04.html">NIP-04</a> — the (deprecated) encryption scheme mandated for private job params.</li>433 <li><a href="44.html">NIP-44</a> — the modern encryption standard that replaced NIP-04.</li>434 <li><a href="09.html">NIP-09</a> — delete requests; used to cancel a job request.</li>435 <li><a href="57.html">NIP-57</a> — zaps; one of the two payment paths for job results.</li>436 </ul>437 </div>438439 <aside>440 <div class="cartridge">441 <div class="inner">442 <h3 class="cardhead">Spec Card</h3>443 <div class="lights"><span class="led err"></span><span class="led err"></span><span class="led err"></span></div>444 <dl>445 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip unrecommended">unrecommended</span><span class="chip">optional</span></dd>446 <dt>Defines</dt><dd>job requests 5000-5999 - results 6000-6999 - feedback 7000 - i/output/param/bid/relays/status/amount/encrypted tags</dd>447 <dt>Kinds</dt><dd>5000-7000 (reserved range)</dd>448 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="04.html">NIP-04</a> (encryption) - <a href="89.html">NIP-89</a> (discovery)</dd>449 <dt>Payment</dt><dd>bolt11 invoice or <a href="57.html">NIP-57</a> zap</dd>450 <dt>First commit</dt><dd>2023-07-25</dd>451 <dt>Last updated</dt><dd>2026-06-13</dd>452 </dl>453 </div>454 </div>455 </aside>456 </main>457458 <nav class="navbtns">459 <a href="89.html">◀ NIP-89: Recommended Application Handlers</a>460 <a href="92.html">NIP-92: Media Attachments Metadata (imeta) ▶</a>461 </nav>462463 <footer class="pagefoot">464 <a href="../index.html">Nostr Protocol Manual</a>465 <span class="pageno">NIP 90 / F4</span>466 </footer>467</div>468469<script src="../assets/webmcp.js" defer></script>470</body>471</html>