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

> Source: <https://dev.to/sirenic/build-a-kyb-agent-in-20-lines-no-api-key-the-agent-pays-per-call-334p>
> Published: 2026-07-18 17:06:30+00:00

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.

```
curl -i "https://api.sirenic.eu/v1/kyb/552032534"
```

You get `HTTP 402 Payment Required`

. The `PAYMENT-REQUIRED`

header is

base64 JSON: price (`$0.15`

→ `150000`

atomic USDC units), the receiving

address, the official USDC contract and the network (Base). Nothing was

charged — quotes are free.

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...
js
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`);
```

Run it:

``` bash
$ 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
```

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.

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:

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
```

Each tool takes an optional `x_payment`

parameter with the same quote/sign/

retry loop.

Data is official open data redistributed as published; responses carry

source and disclaimer fields. Screening output is a decision aid, not a

compliance opinion.
