Hanzo for agents: free to start, pay as you go
Sign up free with a wallet. Get an API key free. A small free allowance to try it. Top up in USDC or USDT over the API to raise your limits and pay as you go. No human required.
Hanzo has built business software since 2014 for hundreds of venture-funded startups, two of which went public. Our track record
Sign a one-time challenge from hanzo.id. A first-seen wallet gets its own account and organization.
What your agent gets, and what it costs
One key opens https://api.hanzo.ai/v1: every model in the catalog, Kai decisions and agents. The figures are read from the API when this page opens.
Free, with a wallet. No inbox, no card, no person.
Free, minted over the API, each with its own monthly budget and rate.
A small free allowance on the new account. With your key, GET https://api.hanzo.ai/v1/billing/tier says what it allows and what is left.
Each call is billed from your balance at its model’s rate in GET /v1/pricing. Kai decisions: … per million input tokens, output free.
USDC or USDT over the API, to raise your limits. A card at hanzo.ai/pay or a bank wire works too, for a person.
From $20 a month; every plan and price at GET https://api.hanzo.ai/v1/billing/plans.
Headless: sign up, get a key, top up
The whole path with no person. Every step is one request, and the script below makes them all; it was run as printed against production.
- Sign up with a wallet: GET hanzo.id/v1/iam/web3/nonce, sign the message with EIP-191, POST hanzo.id/v1/iam/web3/verify, exchange the code at hanzo.id/v1/iam/oauth/token. A first-seen wallet gets its own account and organization.
- Get a key: POST /v1/account/keys with that token. It is shown once.
- Read your allowance: GET /v1/billing/tier with the key.
- Top up: GET /v1/billing/crypto/options, POST /v1/billing/crypto/deposit, send to the address it returns, then GET /v1/billing/crypto/deposit/{id} until it says succeeded.
- Call: POST /v1/chat/completions, and pay as you go.
// No human required: sign up with a wallet, get a key, call the API, top up in USDC or USDT.
// A first-seen wallet gets its own Hanzo account and organization, with a small free allowance to try it.
// npm i viem · node headless.mts (Node 22.18+; set HANZO_WALLET_KEY to use your own wallet)
import { createHash, randomBytes } from 'node:crypto'
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
const ID = 'https://hanzo.id'
const API = 'https://api.hanzo.ai'
const CLIENT = 'hanzo-ai'
const REDIRECT = 'http://localhost:3000/callback'
// Your agent's own wallet, or a fresh one. The key never leaves this process.
const account = privateKeyToAccount((process.env.HANZO_WALLET_KEY as `0x${string}`) ?? generatePrivateKey())
const json = async (r: Response) => {
const body = await r.json()
if (!r.ok || body?.status === 'error') throw new Error(`${r.url} ${r.status} ${JSON.stringify(body)}`)
return body
}
// 1. A one-time challenge for this wallet.
const { data: c } = await json(await fetch(`${ID}/v1/iam/web3/nonce?chain=evm&address=${account.address}`))
// 2. The CAIP-122 message the challenge describes, signed with EIP-191 personal_sign.
const message = [
`${c.domain} wants you to sign in with your Ethereum account:`,
account.address,
'',
...(c.statement ? [c.statement, ''] : []),
`URI: ${c.uri}`,
`Version: ${c.version}`,
`Nonce: ${c.nonce}`,
`Issued At: ${c.issuedAt}`,
...(c.expirationTime ? [`Expiration Time: ${c.expirationTime}`] : []),
].join('\n')
const signature = await account.signMessage({ message })
// 3. Verify: a first-seen wallet gets an account and an organization of its own.
const verifier = randomBytes(32).toString('base64url')
const challenge = createHash('sha256').update(verifier).digest('base64url')
const { data: code } = await json(
await fetch(`${ID}/v1/iam/web3/verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
clientId: CLIENT, chain: 'evm', scheme: 'secp256k1-eip191', address: account.address, message, signature,
type: 'code', redirectUri: REDIRECT, scope: 'openid profile email', codeChallenge: challenge, codeChallengeMethod: 'S256',
}),
}),
)
// 4. The authorization code for a token.
const token = await json(
await fetch(`${ID}/v1/iam/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ grant_type: 'authorization_code', client_id: CLIENT, code, code_verifier: verifier, redirect_uri: REDIRECT }),
}),
)
const bearer = { Authorization: `Bearer ${token.access_token}`, 'Content-Type': 'application/json' }
// 5. A key that outlives the token. Shown once: keep it in your secret store.
const minted = await json(await fetch(`${API}/v1/account/keys`, { method: 'POST', headers: bearer, body: JSON.stringify({ name: 'agent', type: 'secret' }) }))
const key = { Authorization: `Bearer ${minted.key}`, 'Content-Type': 'application/json' }
// 6. A first call, free.
const chat = await fetch(`${API}/v1/chat/completions`, {
method: 'POST', headers: key,
body: JSON.stringify({ model: 'zen-free', messages: [{ role: 'user', content: 'Reply with the single word: ready' }] }),
})
console.log('chat', chat.status, chat.headers.get('x-hanzo-served'), 'free left today:', chat.headers.get('x-ratelimit-remaining'))
console.log((await chat.json()).choices?.[0]?.message?.content)
// 7. Top up in USDC: ask for a deposit address, then send to exactly that address.
console.log(await json(await fetch(`${API}/v1/billing/crypto/options`, { headers: key })))
console.log(await json(await fetch(`${API}/v1/billing/crypto/deposit`, { method: 'POST', headers: key, body: JSON.stringify({ chain: 'base', token: 'usdc', amountCents: 500 }) })))
// 8. The chain's confirmation credits the balance: GET /v1/billing/crypto/deposit/<id> reads it back
// (pending, confirming, succeeded), and GET /v1/billing/tier says what the key may spend now.
console.log('HANZO_API_KEY=' + minted.key.slice(0, 12) + '… (store the whole key; it is shown once)')Keep the wallet key and the API key in your secret store: the wallet is the account, and the API key is shown once. A deposit address lasts 24 hours and is credited when the chain confirms; send only the token and chain it names.
Paste this into your agent
What Hanzo is, the base URL, how to discover the API and the headless path, in one block an agent keeps in its context.
Hanzo (https://hanzo.ai) is the AI operating system for business: one API for every model, Kai decisions and agents, with one key. Building business software since 2014. Techstars '17.
Sign up free with a wallet. Get an API key free. A small free allowance to try it. Top up in USDC or USDT over the API to raise your limits and pay as you go. No human required.
Base URL: https://api.hanzo.ai/v1 (chat completions in the OpenAI shape). Discover: GET https://api.hanzo.ai/v1 lists every capability, GET https://api.hanzo.ai/v1/<capability> its operations, and https://api.hanzo.ai/v1/openapi.json is the whole spec. No key needed for any of the three.
1. Sign up with a wallet: GET https://hanzo.id/v1/iam/web3/nonce?chain=evm&address=<address>, sign the CAIP-122 message it describes with EIP-191 personal_sign, POST https://hanzo.id/v1/iam/web3/verify (clientId "hanzo-ai", chain "evm", scheme "secp256k1-eip191", type "code" with a PKCE challenge), then exchange the code at https://hanzo.id/v1/iam/oauth/token. A first-seen wallet gets its own account and organization. A Solana wallet asks with chain=solana, writes "Solana account" in the message, and sends chain "solana", scheme "ed25519" and its signature as base64, never base58.
2. Get a key: POST https://api.hanzo.ai/v1/account/keys {"name":"agent","type":"secret"} with that token. The key is shown once.
3. Read your allowance: GET https://api.hanzo.ai/v1/billing/tier with the key says your plan, what it allows and what is left; GET https://api.hanzo.ai/v1/billing/plans lists every plan and price.
4. Top up: GET https://api.hanzo.ai/v1/billing/crypto/options, then POST https://api.hanzo.ai/v1/billing/crypto/deposit {"chain":"base","token":"usdc","amountCents":2000}. Send that token on that chain to the address it returns, and GET https://api.hanzo.ai/v1/billing/crypto/deposit/<id> until it says succeeded.
5. Call: POST https://api.hanzo.ai/v1/chat/completions {"model":"zen-free","messages":[{"role":"user","content":"Hello"}]} with Authorization: Bearer <key>.
The whole path as one TypeScript file: https://hanzo.ai/agents#headless. Every request spelled out: https://docs.hanzo.ai/docs/agents. Talk to people at Hanzo: https://cal.com/hanzo.Results on Hanzo
What companies have done on the platform, each beside the page that shows it.
You are a builder agent
With a person nearby: five steps from nothing to a working call, a tool server and your own measurement of Kai.
Get a credential
Install the CLI and sign in. On a machine with no browser it prints a link and an 8-character code, and your person approves it on any device. The token works as a bearer at once; mint a key for anything that runs longer than an hour.
curl -fsSL https://hanzo.sh | sh
hanzo auth login # no browser here? it prints a link and a code
export HANZO_API_KEY="$(hanzo auth token)"
hanzo account keys create --name agent --type secret # a key for a serverMake the first call
zen-free costs nothing. The answer is the chat completions shape you already parse, and its headers say which model answered and how many free requests are left today.
curl https://api.hanzo.ai/v1/chat/completions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"zen-free","messages":[{"role":"user","content":"Hello"}]}'Give your editor the tools
The same server loads in Codex, Cursor and Zed; their config files are on the docs page.
claude mcp add hanzo --env HANZO_API_KEY=$HANZO_API_KEY \
-- npx -y --package=@hanzo/mcp@latest hanzo-mcp serveMeasure Kai yourself
Kai answers typed questions with probabilities over the options you name and writes no text, so usage.output_tokens is 0.
curl https://api.hanzo.ai/v1/decisions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"kai",
"state":{"ticket":"The export button throws a 500 error since this morning."},
"questions":{"team":{"type":"choice",
"instructions":"Which team should handle this ticket?",
"criteria":{"billing":"charges, invoices, refunds",
"tech":"bugs, errors, outages",
"other":"anything else"}}}}'
# {"answers":{"team":{"choice":"tech","confidence":0.951, ...}},
# "usage":{"input_tokens":41,"output_tokens":0}, "latency_ms":121.2}Run the frozen harness
The harness that produced the published results is public. Three cases from four suites is 12 requests; the full harness is 9,499. The full runs are readable with no key at api.hanzo.ai/v1/research/runs.
git clone --depth 1 https://github.com/hanzoai/benchmarks && cd benchmarks/decision
python3 harness/run_kai.py --limit 3 --out $PWD/kai.json.gz \
--suites app.phishing,app.support_triage,app.email_spam,app.rag_relevance
uv run --with numpy python harness/merge.py --kai $PWD/kai.json.gz --out $PWD/out
cat out/table.md # Kai beside Jev's recorded answers, suite by suiteRun a campaign
Measure the site, have a model write the variants, and stage the campaign as a draft. A draft sends nothing and commits no budget; the launch spends it, so a person presses launch.
curl "https://api.hanzo.ai/v1/event/overview?range=7d" -H "Authorization: Bearer $HANZO_API_KEY"
curl https://api.hanzo.ai/v1/campaign \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Spring launch","audience":"returning-visitors",
"content":["Variant A, written by zen-free","Variant B"],
"budget":50000,
"channels":[{"kind":"paid","platform":"meta"},{"kind":"email"}]}'
# a draft: nothing sent, no budget committed until POST /v1/campaign/{id}/launch
# then: GET /v1/campaign/{id}/metrics?range=7d (CTR, CVR, CAC, ROAS per channel)Paid channels run through the ad accounts your organization connects (Meta, Google, X); email goes out from your organization with an unsubscribe link on every message. Metrics read the same analytics your event tag writes.
You run builder agents
An account for your team, a budget on every agent, and a bill you can pay the way your agents can.
- Sign up once. The account founds an organization you administer; Team is sold by the member, for 2 to 100 people, with single sign-on, roles and an audit log.
- Bound every agent. A key takes a monthly budget in cents, a rate in requests a minute, the models and projects it may reach, and an expiry. A session takes its own cap in micro-dollars, and pauses when it reaches it.
- Pay by card, Apple Pay or Google Pay at hanzo.ai/pay, or fund the balance in USDC or USDT over the API. Wire instructions come from GET /v1/billing/wire to a signed-in caller, and a wire is credited once the bank confirms it.
- Talk to the people who build it: book a call at cal.com/hanzo.
Everything an agent can read
Questions
What is free?
What does it cost after that?
Can an agent sign up without a person?
How does an agent pay?
How do I keep an agent from overspending?
Which tools can my agent use?
Hanzo AI: building business software since 2014. Techstars '17. About Hanzo