<?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: Carlos Soto</title>
    <description>The latest articles on DEV Community by Carlos Soto (@carlos_soto_).</description>
    <link>https://dev.to/carlos_soto_</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%2F1592596%2F8ce25d62-4975-4843-8aeb-e35054115e76.png</url>
      <title>DEV Community: Carlos Soto</title>
      <link>https://dev.to/carlos_soto_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/carlos_soto_"/>
    <language>en</language>
    <item>
      <title>Let your AI agent place a real phone call, paid per call in USDC</title>
      <dc:creator>Carlos Soto</dc:creator>
      <pubDate>Tue, 03 Nov 2026 05:21:05 +0000</pubDate>
      <link>https://dev.to/agentgates/let-your-ai-agent-place-a-real-phone-call-paid-per-call-in-usdc-1j7a</link>
      <guid>https://dev.to/agentgates/let-your-ai-agent-place-a-real-phone-call-paid-per-call-in-usdc-1j7a</guid>
      <description>&lt;p&gt;An agent that needs to call a restaurant, a clinic or a shop usually hits a wall: phone APIs want an account, a verified number and a card on file. &lt;a href="https://agentgates.ai" rel="noopener noreferrer"&gt;Agentgates&lt;/a&gt; runs a payphone instead. The agent pays for a window of minutes, names the number, and the call goes out from a house number. Nothing is stored and nothing renews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the windows, free
&lt;/h2&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://agentgates.ai/api/booth | jq &lt;span class="s1"&gt;'.windows'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each window is a number of minutes and its price, read live.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who talks
&lt;/h2&gt;

&lt;p&gt;Every call names who is on our side of the line.&lt;/p&gt;

&lt;p&gt;Your own phone: send &lt;code&gt;bridgeTo&lt;/code&gt; with your number and the booth rings you first, then connects you to &lt;code&gt;to&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Your agent's own voice: send &lt;code&gt;streamUrl&lt;/code&gt; and the call's audio becomes a bidirectional websocket, so an agent with its own speech and its own ears talks to the person directly. Frames are raw mulaw at 8 kHz, 20 ms each (160 bytes), base64 in &lt;code&gt;{"event":"media","media":{"payload":"..."}}&lt;/code&gt;. Send raw mulaw, not RTP: a 12-byte RTP header on outbound frames plays as a click every 20 ms.&lt;/p&gt;

&lt;p&gt;Our operator: send &lt;code&gt;task&lt;/code&gt;, a plain sentence of what to get done, and an AI operator makes the call and answers with the transcript and the outcome.&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; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://agentgates.ai/api/booth &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;'{"kind":"call","minutes":5,"to":"+15551234567","task":"Ask what time they open tomorrow."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The 402 is the price
&lt;/h2&gt;

&lt;p&gt;That request comes back &lt;code&gt;402 Payment Required&lt;/code&gt; with the exact USDC amount on each network it accepts. Nothing is dialed yet. Sign that amount with the paying wallet and send the same request again with the payment attached; any x402 client does both steps. Then the phone rings.&lt;/p&gt;

&lt;p&gt;A call that never connects can be placed again with the same payment at no charge, and the agent can end the call early by sending &lt;code&gt;{"kind":"call","hangup":true}&lt;/code&gt; with that payment.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the agent needs a number of its own
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /api/account/plans&lt;/code&gt; leases a number for a month. It receives texts and places calls, and it belongs to the agent's account for the term. The account is twelve words the agent keeps, made with one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @agentgates/cli &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; agentgates init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  For agents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The phone contract, written for software: &lt;a href="https://api.agentgates.ai/api/account/docs/phone" rel="noopener noreferrer"&gt;&lt;code&gt;/api/account/docs/phone&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Skills for coding agents: &lt;code&gt;npx skills add agentgates-ai/agentgates&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Every price, read live: &lt;a href="https://agentgates.ai/pricing" rel="noopener noreferrer"&gt;agentgates.ai/pricing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only call people who agreed to hear from you: &lt;a href="https://agentgates.ai/terms" rel="noopener noreferrer"&gt;terms&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>x402</category>
      <category>voice</category>
    </item>
    <item>
      <title>Rent a confidential VM with USDC in two HTTP requests, no signup</title>
      <dc:creator>Carlos Soto</dc:creator>
      <pubDate>Tue, 03 Nov 2026 05:21:04 +0000</pubDate>
      <link>https://dev.to/agentgates/rent-a-confidential-vm-with-usdc-in-two-http-requests-no-signup-3d9h</link>
      <guid>https://dev.to/agentgates/rent-a-confidential-vm-with-usdc-in-two-http-requests-no-signup-3d9h</guid>
      <description>&lt;p&gt;Most cloud APIs assume a person: a signup form, a card, an API key pasted into a config file. An agent that needs a machine for an hour has none of those. It has a wallet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://agentgates.ai" rel="noopener noreferrer"&gt;Agentgates&lt;/a&gt; sells confidential VMs (Intel TDX) by the hour to exactly that buyer. There is no account. The wallet that pays owns the machine, reads its state, renews it and destroys it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 402 is the quote
&lt;/h2&gt;

&lt;p&gt;Ask for a machine with no payment and the API answers &lt;code&gt;402 Payment Required&lt;/code&gt; with the exact price on every network it accepts. Asking is free and repeatable: nothing runs and nothing is charged.&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; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.agentgates.ai/api/compute/deployments &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;'{"plan":"compute.starter","hours":1,"image":"nginx:alpine"}'&lt;/span&gt; |
  jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.accepts[] | "\(.network): \((.maxAmountRequired | tonumber) / 1000000) USDC"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each entry of &lt;code&gt;accepts&lt;/code&gt; is one network's own offer: the amount in USDC atomic units, the token contract and the address to pay. The plans and their live prices are in &lt;code&gt;GET /api/compute/catalog&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pay that amount, send the same request again
&lt;/h2&gt;

&lt;p&gt;Sign the amount (an EIP-3009 transfer authorization on Base or Polygon, a transfer on Solana) and resend the same request with the payment attached. The official x402 v2 client does both steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;wrapFetchWithPaymentFromConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@x402/fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ExactEvmScheme&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@x402/evm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;privateKeyToAccount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem/accounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wrapFetchWithPaymentFromConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;schemes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eip155:8453&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExactEvmScheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;privateKeyToAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EVM_PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.agentgates.ai/api/compute/deployments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;compute.starter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nginx:alpine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// { deploymentId, status: "provisioning", ... }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Settlement confirms on chain, the machine provisions, and the billed clock starts when it reads &lt;code&gt;running&lt;/code&gt;, not at payment. A wallet that cannot cover the amount is refused before anything moves: the answer says how much it needs and how much it holds.&lt;/p&gt;

&lt;p&gt;The full example, which prints the price and pays only with &lt;code&gt;--yes&lt;/code&gt;, is in &lt;a href="https://github.com/agentgates-ai/agentgates/blob/main/examples/buy-a-vm.mjs" rel="noopener noreferrer"&gt;the repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why confidential
&lt;/h2&gt;

&lt;p&gt;The machine's memory and disk are encrypted by the processor, and every machine carries a remote-attestation quote with a public proof page, so you can check the hardware before you hand it a secret. Environment values you send are sealed to the machine and never stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep it running
&lt;/h2&gt;

&lt;p&gt;Watch &lt;code&gt;expiresAt&lt;/code&gt; and renew with &lt;code&gt;POST /api/compute/deployments/{id}/renew&lt;/code&gt; and &lt;code&gt;{"hours": 1}&lt;/code&gt;, paid the same way. Renewals stack on the end of the clock, so an agent can keep a machine alive an hour at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  For agents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The contract, written for software: &lt;a href="https://api.agentgates.ai/api/compute/docs" rel="noopener noreferrer"&gt;&lt;code&gt;/api/compute/docs&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An MCP server with no sign-in that lists plans and prices a machine: &lt;code&gt;https://mcp.agentgates.ai/compute&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Skills for coding agents: &lt;code&gt;npx skills add agentgates-ai/agentgates&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Every price, read live: &lt;a href="https://agentgates.ai/pricing" rel="noopener noreferrer"&gt;agentgates.ai/pricing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>x402</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
