<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kaven C</title>
    <description>The latest articles on DEV Community by Kaven C (@linknpark).</description>
    <link>https://dev.to/linknpark</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4013694%2F7ba5288f-40e2-427d-bbe2-3fd5233c8f9d.webp</url>
      <title>DEV Community: Kaven C</title>
      <link>https://dev.to/linknpark</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/linknpark"/>
    <language>en</language>
    <item>
      <title>I built an "agent door" — how AI agents pay per action on my helpdesk (MCP + x402)</title>
      <dc:creator>Kaven C</dc:creator>
      <pubDate>Fri, 03 Jul 2026 13:30:43 +0000</pubDate>
      <link>https://dev.to/linknpark/i-built-an-agent-door-how-ai-agents-pay-per-action-on-my-helpdesk-mcp-x402-3ng8</link>
      <guid>https://dev.to/linknpark/i-built-an-agent-door-how-ai-agents-pay-per-action-on-my-helpdesk-mcp-x402-3ng8</guid>
      <description>&lt;p&gt;Most "AI + payments" stories are about humans buying things through an agent. I wanted the opposite: an &lt;strong&gt;anonymous AI agent that shows up, does one unit of work, and pays for it — no account, no API key, no human in the loop.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I built it into a helpdesk. Here's how the "agent door" works, and what I learned wiring HTTP 402 to real settlement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with giving agents API keys
&lt;/h2&gt;

&lt;p&gt;The default way to let an agent use your API is: a human signs up, adds a card, generates a key, and manages it. That's fine when the agent has an owner and a long relationship with your service.&lt;/p&gt;

&lt;p&gt;It's terrible when the agent is &lt;em&gt;ephemeral&lt;/em&gt; — it needs one action, right now, and will never come back. Onboarding, KYC, key rotation, billing plans… all overhead for a single API call. There's no clean "walk up and pay for exactly what you use" primitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The primitive: HTTP 402 + x402
&lt;/h2&gt;

&lt;p&gt;HTTP has always had a status code reserved for this: &lt;strong&gt;&lt;code&gt;402 Payment Required&lt;/code&gt;&lt;/strong&gt;. It was never really used — until &lt;a href="https://x402.org" rel="noopener noreferrer"&gt;x402&lt;/a&gt; gave it a concrete meaning: the server responds &lt;code&gt;402&lt;/code&gt; with machine-readable payment terms, the client pays (USDC on-chain), and retries the same request with an &lt;code&gt;X-PAYMENT&lt;/code&gt; header. Settlement happens per request.&lt;/p&gt;

&lt;p&gt;No account. No API key. The payer's wallet &lt;em&gt;is&lt;/em&gt; the identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The door
&lt;/h2&gt;

&lt;p&gt;My helpdesk (&lt;a href="https://deskcrew.io" rel="noopener noreferrer"&gt;DeskCrew&lt;/a&gt;) exposes an &lt;strong&gt;MCP server&lt;/strong&gt; per workspace, so an AI agent can operate the desk — search the knowledge base, open and triage tickets, draft and post replies. Read tools are free; write/AI tools are priced.&lt;/p&gt;

&lt;p&gt;You can hit it right now, no signup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://deskcrew.io/api/mcp/deskcrew &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"tools/list"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That returns the tool catalog with per-tool prices. Call a &lt;em&gt;paid&lt;/em&gt; tool and you get the challenge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"x402Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Payment required for tool 'create_ticket'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accepts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"scheme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"network"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"base"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"maxAmountRequired"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"asset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"payTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"maxTimeoutSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;per&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;chain:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;polygon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;avalanche&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sei&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;solana&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;20000&lt;/code&gt; is &lt;code&gt;$0.02&lt;/code&gt; in USDC's 6 decimals. The agent signs a payment authorization for that amount, retries with &lt;code&gt;X-PAYMENT&lt;/code&gt;, and the tool runs once settlement confirms.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually had to get right
&lt;/h2&gt;

&lt;p&gt;The happy path is easy. The interesting part is everything that isn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The amount, recipient, and asset come from the server — never the client.&lt;/strong&gt; The client sends only a &lt;em&gt;signed&lt;/em&gt; authorization. The server builds the payment terms (price from a server-side table, &lt;code&gt;payTo&lt;/code&gt; = a cold wallet, the USDC contract pinned per chain) and verifies the signature satisfies &lt;em&gt;those&lt;/em&gt; terms. Otherwise an agent could "pay" 1 wei, redirect payment to itself, or hand you a fake token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Don't run a side-effecting action before you're paid — but don't double-charge either.&lt;/strong&gt; &lt;code&gt;verify()&lt;/code&gt; only &lt;em&gt;reads&lt;/em&gt; the payer's balance; it's not a reservation. So N concurrent requests from one wallet funded for a single call can all pass verify. I gate it two ways: an &lt;strong&gt;at-most-one-in-flight lease per wallet&lt;/strong&gt;, and a claimed &lt;strong&gt;nonce&lt;/strong&gt; (EIP-3009) inserted &lt;em&gt;before&lt;/em&gt; the action runs, so a replay or a concurrent duplicate can't execute the tool twice for one payment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. For live external effects (like sending a customer an email), settle &lt;em&gt;first&lt;/em&gt;.&lt;/strong&gt; The fairness default is "only charge on success" — so most tools run, then settle. But for the one action where "ran but not charged" is real abuse (a free outbound email from your domain), I flipped the order: confirm payment on-chain, &lt;em&gt;then&lt;/em&gt; send. The safe failure direction is "paid but not delivered," never "delivered for free."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Anonymous ≠ unbounded.&lt;/strong&gt; Per-wallet rate/spend caps, reputation, and a deliverability breaker bound abuse. High-value actions are gated behind &lt;em&gt;earned&lt;/em&gt; reputation, so a day-one anonymous wallet can't email your customers — it gets a draft in a human approval queue instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Self-host the money path.&lt;/strong&gt; I run my own relayer + facilitator, so there's no third party between the agent and settlement. USDC lands in a cold wallet at my prices; even a leaked hot key can only move the payer's funds &lt;em&gt;to my wallet, at my price&lt;/em&gt; (the settle is economically bound).&lt;/p&gt;

&lt;h2&gt;
  
  
  Was it worth it?
&lt;/h2&gt;

&lt;p&gt;For a helpdesk specifically: an agent resolving a support task mid-workflow can now pay for exactly the tools it uses — no account, no key. Whether &lt;em&gt;pay-per-action&lt;/em&gt; beats &lt;em&gt;just issue the agent a key&lt;/em&gt; is genuinely situational, and I'd love the internet's opinion on where the line is.&lt;/p&gt;

&lt;p&gt;But the pattern is bigger than helpdesks. &lt;code&gt;402&lt;/code&gt; + a signed micropayment is the missing "walk up and pay" primitive for the agent web. It's early and rough, but it works today — you just curled it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://deskcrew.io" rel="noopener noreferrer"&gt;deskcrew.io&lt;/a&gt; · the door: &lt;code&gt;POST https://deskcrew.io/api/mcp/deskcrew&lt;/code&gt; · MCP spec + tools: &lt;a href="https://github.com/webmilmind1/deskcrew-mcp" rel="noopener noreferrer"&gt;github.com/webmilmind1/deskcrew-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy to answer anything about the x402 wiring in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>webdev</category>
      <category>crypto</category>
    </item>
  </channel>
</rss>
