<?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: Come</title>
    <description>The latest articles on DEV Community by Come (@sirenic).</description>
    <link>https://dev.to/sirenic</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%2F4033871%2Fa4aad073-b3ff-45c3-aa60-288067456d06.png</url>
      <title>DEV Community: Come</title>
      <link>https://dev.to/sirenic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sirenic"/>
    <language>en</language>
    <item>
      <title>Build a KYB agent in 20 lines no API key, the agent pays per call</title>
      <dc:creator>Come</dc:creator>
      <pubDate>Sat, 18 Jul 2026 17:06:30 +0000</pubDate>
      <link>https://dev.to/sirenic/build-a-kyb-agent-in-20-lines-no-api-key-the-agent-pays-per-call-334p</link>
      <guid>https://dev.to/sirenic/build-a-kyb-agent-in-20-lines-no-api-key-the-agent-pays-per-call-334p</guid>
      <description>&lt;p&gt;AI agents have a boring problem: they can't sign up for things. Every&lt;br&gt;
interesting API sits behind an email verification, a credit-card form and an&lt;br&gt;
API key — three things a headless agent can't do. I ran into this building my&lt;br&gt;
own agents, so I ended up building an API the other way round, and this is the&lt;br&gt;
20-line version of what it makes possible.&lt;/p&gt;

&lt;p&gt;We'll build a working KYB (Know Your Business) agent in ~20 lines of&lt;br&gt;
TypeScript. It verifies any French company — identity, officers, insolvency&lt;br&gt;
alerts, filed financials, sanctions screening — and it pays for what it uses,&lt;br&gt;
per call, in USDC. No account anywhere.&lt;/p&gt;
&lt;h2&gt;
  
  
  The building blocks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/x402-foundation/x402" rel="noopener noreferrer"&gt;x402&lt;/a&gt;&lt;/strong&gt; — an open protocol
that revives HTTP 402: the server answers a machine-readable payment
quote; the client signs a stablecoin authorization and retries. One
round-trip, no gas for the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://api.sirenic.eu" rel="noopener noreferrer"&gt;Sirenic&lt;/a&gt;&lt;/strong&gt; — a pay-per-call API over official
French/European company registers (INSEE/INPI open data, Etalab 2.0
license). Prices from $0.001. Disclosure: I built it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 1 — look at a quote (no wallet yet)
&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;-i&lt;/span&gt; &lt;span class="s2"&gt;"https://api.sirenic.eu/v1/kyb/552032534"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You get &lt;code&gt;HTTP 402 Payment Required&lt;/code&gt;. The &lt;code&gt;PAYMENT-REQUIRED&lt;/code&gt; header is&lt;br&gt;
base64 JSON: price (&lt;code&gt;$0.15&lt;/code&gt; → &lt;code&gt;150000&lt;/code&gt; atomic USDC units), the receiving&lt;br&gt;
address, the official USDC contract and the network (Base). Nothing was&lt;br&gt;
charged — quotes are free.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2 — a wallet for your agent
&lt;/h2&gt;

&lt;p&gt;Create a throwaway wallet (MetaMask works), export the private key, and&lt;br&gt;
fund it with a couple of dollars of USDC on &lt;strong&gt;Base&lt;/strong&gt; (any exchange can&lt;br&gt;
withdraw to Base). The &lt;code&gt;exact&lt;/code&gt; payment scheme uses signed authorizations,&lt;br&gt;
so the client never pays gas — USDC is all the wallet needs. The whole&lt;br&gt;
tutorial costs $0.15.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @x402/fetch @x402/core @x402/evm viem tsx
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TEST_WALLET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — the agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;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="s2"&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;wrapFetchWithPayment&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="s2"&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;x402Client&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="s2"&gt;@x402/core/client&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;registerExactEvmScheme&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="s2"&gt;@x402/evm/exact/client&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;siren&lt;/span&gt; &lt;span class="o"&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;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;552032534&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;x402Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;registerExactEvmScheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;signer&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;TEST_WALLET_KEY&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="s2"&gt;`0x&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;payingFetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wrapFetchWithPayment&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="nx"&gt;client&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;kyb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;payingFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`https://api.sirenic.eu/v1/kyb/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;siren&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&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="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;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="s2"&gt;`Company : &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;denomination&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siren&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) — &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;etat_administratif&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;`Officers: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dirigeants&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | VAT: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tva_intracommunautaire&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;`Alerts  : &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alertes_bodacc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;procedures_collectives&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n/a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; insolvency proceedings`&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="s2"&gt;`Sanctions screening: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;criblage_sanctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statut&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;`Completeness: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kyb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score_completude&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/100`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npx tsx kyb-agent.ts 552032534
&lt;span class="go"&gt;Company : DANONE (552032534) — actif
Officers: 13 | VAT: FR27552032534
Alerts  : 0 insolvency proceedings
Sanctions screening: correspondances_a_verifier
Completeness: 100/100
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole agent. &lt;code&gt;wrapFetchWithPayment&lt;/code&gt; intercepted the 402, signed&lt;br&gt;
a $0.15 USDC authorization, retried, and the API released the response once&lt;br&gt;
the settlement was confirmed on-chain.&lt;/p&gt;
&lt;h2&gt;
  
  
  What actually happened in that one call
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;/v1/kyb/{siren}&lt;/code&gt; endpoint consolidates six sources server-side:&lt;br&gt;
registry identity and officers, BODACC legal announcements, filed accounts,&lt;br&gt;
and a fuzzy sanctions screening of the company name &lt;strong&gt;and every officer&lt;/strong&gt;&lt;br&gt;
against the five official lists (UN, EU, OFAC, UK, French asset-freeze&lt;br&gt;
register). Matches come back with a 0-100 confidence score and the matched&lt;br&gt;
alias — never a bare yes/no, because "Emmanuel Macron vs. Emmanuel Sultani&lt;br&gt;
Makenga" is exactly the kind of thing you want a human to look at.&lt;/p&gt;

&lt;p&gt;Two production details worth stealing for your own paid APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Never charge for errors.&lt;/strong&gt; If the company doesn't exist (404) or a
source fails (503), the verified payment is cancelled — the agent pays
nothing. Agents can't file support tickets; your error semantics are
your support team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A completeness score beats silent gaps.&lt;/strong&gt; If one upstream source is
down, the response says which block is missing and why, and the score
drops. The agent can decide whether 80/100 is good enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  MCP, if you'd rather not write code
&lt;/h2&gt;

&lt;p&gt;The same API is an MCP server — Claude and Cursor can use it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http sirenic https://api.sirenic.eu/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tool takes an optional &lt;code&gt;x_payment&lt;/code&gt; parameter with the same quote/sign/&lt;br&gt;
retry loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Examples repo (this code + more): &lt;a href="https://github.com/sirenic-eu/sirenic-examples" rel="noopener noreferrer"&gt;https://github.com/sirenic-eu/sirenic-examples&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OpenAPI: &lt;a href="https://api.sirenic.eu/openapi.json" rel="noopener noreferrer"&gt;https://api.sirenic.eu/openapi.json&lt;/a&gt; · llms.txt: &lt;a href="https://api.sirenic.eu/llms.txt" rel="noopener noreferrer"&gt;https://api.sirenic.eu/llms.txt&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data is official open data redistributed as published; responses carry&lt;br&gt;
source and disclaimer fields. Screening output is a decision aid, not a&lt;br&gt;
compliance opinion.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>api</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
