DEV Community

Cover image for Build a KYB agent in 20 lines no API key, the agent pays per call
Come
Come

Posted on

Build a KYB agent in 20 lines no API key, the agent pays per call

AI agents have a boring problem: they can't sign up for things. Every
interesting API sits behind an email verification, a credit-card form and an
API key — three things a headless agent can't do. I ran into this building my
own agents, so I ended up building an API the other way round, and this is the
20-line version of what it makes possible.

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

The building blocks

  • x402 — 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.
  • Sirenic — 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.

Step 1 — look at a quote (no wallet yet)

curl -i "https://api.sirenic.eu/v1/kyb/552032534"
Enter fullscreen mode Exit fullscreen mode

You get HTTP 402 Payment Required. The PAYMENT-REQUIRED header is
base64 JSON: price ($0.15150000 atomic USDC units), the receiving
address, the official USDC contract and the network (Base). Nothing was
charged — quotes are free.

Step 2 — a wallet for your agent

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

npm install @x402/fetch @x402/core @x402/evm viem tsx
export TEST_WALLET_KEY=0x...
Enter fullscreen mode Exit fullscreen mode

Step 3 — the agent

import { privateKeyToAccount } from "viem/accounts";
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";

const siren = process.argv[2] ?? "552032534";
const client = new x402Client();
registerExactEvmScheme(client, {
  signer: privateKeyToAccount(process.env.TEST_WALLET_KEY as `0x${string}`),
});
const payingFetch = wrapFetchWithPayment(fetch, client);

const kyb = await (await payingFetch(
  `https://api.sirenic.eu/v1/kyb/${siren}`,
)).json() as Record<string, any>;

console.log(`Company : ${kyb.identite.denomination} (${kyb.siren}) — ${kyb.identite.etat_administratif}`);
console.log(`Officers: ${kyb.identite.dirigeants?.length ?? 0} | VAT: ${kyb.tva_intracommunautaire}`);
console.log(`Alerts  : ${kyb.alertes_bodacc.procedures_collectives?.length ?? "n/a"} insolvency proceedings`);
console.log(`Sanctions screening: ${kyb.criblage_sanctions.statut}`);
console.log(`Completeness: ${kyb.score_completude}/100`);
Enter fullscreen mode Exit fullscreen mode

Run it:

$ npx tsx kyb-agent.ts 552032534
Company : DANONE (552032534) — actif
Officers: 13 | VAT: FR27552032534
Alerts  : 0 insolvency proceedings
Sanctions screening: correspondances_a_verifier
Completeness: 100/100
Enter fullscreen mode Exit fullscreen mode

That's the whole agent. wrapFetchWithPayment intercepted the 402, signed
a $0.15 USDC authorization, retried, and the API released the response once
the settlement was confirmed on-chain.

What actually happened in that one call

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

Two production details worth stealing for your own paid APIs:

  • Never charge for errors. 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.
  • A completeness score beats silent gaps. 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.

MCP, if you'd rather not write code

The same API is an MCP server — Claude and Cursor can use it directly:

claude mcp add --transport http sirenic https://api.sirenic.eu/mcp
Enter fullscreen mode Exit fullscreen mode

Each tool takes an optional x_payment parameter with the same quote/sign/
retry loop.

Links

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

Top comments (0)