API Reference
Public HTTP routes exposed by agtnames.com. They power the site's search, directory, migration and registration flows, and you can call them directly with any HTTP client. For programmatic resolution of a name, prefer the Resolver SDK or the MCP server: they read the registry directly and need no intermediary.
Lookups
GET /api/search Live
Rate limit: 30 per minute
Check one name: is it available, reserved for an existing holder to migrate, or taken — and what it costs. name is a label, with or without .agt.
curl "https://agtnames.com/api/search?name=demoagent"{
"success": true, "name": "demoagent", "fullDomain": "demoagent.agt", "registry": "v2",
"tier": "standard", "registrationOpen": true,
"status": "unavailable", "available": false, "reserved": false,
"price": null, "registerUsd": 10, "renewUsd": 10, "priceNote": "per year"
}{
"success": true, "name": "zzqv-test-9931", "fullDomain": "zzqv-test-9931.agt", "registry": "v2",
"tier": "standard", "registrationOpen": false,
"status": "available", "available": true, "reserved": false,
"price": { "currency": "USD", "amount": 10 }, "registerUsd": 10, "renewUsd": 10, "priceNote": "per year"
}status is one of available, reserved (held for its existing holder to migrate), unavailable or protected. registrationOpen is false until the sales cutover. price is the year-one price; names are annual, so renewUsd is what each further year costs and priceNote is the wording shown beside the price (per year when the two match, otherwise first year, then $N/yr). Migrated names are perpetual and never renew. Errors: 400 for a missing or invalid label (1–63 characters of a-z 0-9 -), 429 when rate limited.
GET /api/agents Live
Rate limit: 20 per minute
The agent directory: every active name the indexer knows, with the endpoint records it has on chain and the capability ids from its verified manifest. Filters: protocol (mcp, a2a, http, ws), capability (exact id, e.g. fact-checking) and q (text match on name and description).
curl "https://agtnames.com/api/agents?protocol=mcp&capability=fact-checking"{
"success": true, "count": 1,
"agents": [{
"domain": "demoagent.agt", "version": 2,
"name": null, "description": null, "icon": null, "website": null,
"protocols": ["mcp", "a2a", "http"],
"capabilities": ["question-answering", "knowledge-retrieval", "fact-checking", "api-integration"],
"endpoints": [{ "protocol": "mcp", "url": "https://demoagent.agts.dev/mcp", "live": true },
{ "protocol": "a2a", "url": "https://demoagent.agts.dev/a2a", "live": true },
{ "protocol": "http", "url": "https://demoagent.agts.dev", "live": true }],
"pricing": null,
"owner": "0x37007a1c233f00b423bc0d177ac5b50ca9417596", "manifestUri": "https://agts.dev/demoagent.json", "perpetual": true
}]
}GET /api/v2/agent-card/<label> Live
Rate limit: 60 per minute
An A2A agent card for the name, built from its verified manifest: url is the a2a endpoint, skills come from the capability ids, provider from the owner and website. Frameworks that take a card URL (Google ADK RemoteA2aAgent, Microsoft Agent Framework A2AAgent) can call the agent with nothing else configured; see Framework integrations.
curl https://agtnames.com/api/v2/agent-card/notary{
"protocolVersion": "1.0", "name": "notary.agt", "description": "…",
"url": "https://…/a2a", "preferredTransport": "JSONRPC", "version": "2026-09-17T…",
"provider": { "organization": "…", "url": "…" },
"capabilities": { "streaming": false, "pushNotifications": false, "stateTransitionHistory": false },
"defaultInputModes": ["text/plain"], "defaultOutputModes": ["text/plain"],
"skills": [{ "id": "fact-checking", "name": "Fact Checking", "description": "…", "tags": ["fact-checking", "agt"] }],
"documentationUrl": "https://agtnames.com/name/notary", "supportsAuthenticatedExtendedCard": false
}404 { "error": "No A2A endpoint" } when the name publishes none. An unverified manifest yields a card with only the on-chain endpoint and a description that says so.
GET /api/badge/<label>.svg Live
Rate limit: 60 per minute
The on-chain identity badge for any valid label as SVG — the same art a mint embeds, so it renders for names that are not registered yet. Cached immutably; safe to hot-link.
curl -o demoagent.svg "https://agtnames.com/api/badge/demoagent.svg"
# content-type: image/svg+xml; cache-control: public, max-age=31536000, immutable<img src="https://agtnames.com/api/badge/demoagent.svg" alt="demoagent.agt identity badge" width="256" height="256" />400 for an invalid label; 503 if the on-chain renderer cannot be read (not cached).
GET /api/health Live
curl https://agtnames.com/api/health{ "ok": true, "service": "agt-site", "registryMode": "claims-only", "durableStorage": true, "time": "2026-09-13T00:22:47.994Z" }registryMode is claims-only while migration is open and new-name sales are closed; it becomes v2 at the sales cutover.
Holders
GET /api/v2/activity Live
Rate limit: 60 per minute
What happened on the registry: totals for every live name plus the last window by kind (registered, migrated, gifted, renewed, manifest) and the most recent events, from the same index as the directory. hours defaults to 24 (max 720), limit to 50 (max 200). Rendered at /activity.
curl "https://agtnames.com/api/v2/activity?hours=24&limit=5"{
"summary": {
"totals": { "names": 120, "perpetual": 100, "annual": 20, "withManifest": 4 },
"window": { "since": "2026-09-16T22:00:00.000Z", "registered": 1, "migrated": 2, "gifted": 42, "renewed": 0, "manifest": 2 }
},
"events": [{
"kind": "registered", "label": "voicemail", "owner": "0x7f4a…7566",
"block": 93984890, "txHash": "0x…", "at": "2026-09-17T21:59:12.000Z", "detail": { "expiry": "1821218368" }
}]
}GET /api/v2/names Live
Rate limit: 60 per minute
Every Registry v2 name a wallet owns, from the index (it trails the chain by up to ten minutes). Backs My agts.
curl "https://agtnames.com/api/v2/names?owner=0x37007a1c233f00b423bc0d177ac5b50ca9417596"{
"owner": "0x37007a1c233f00b423bc0d177ac5b50ca9417596", "count": 68,
"names": [{
"label": "demoagent",
"tokenId": "86495407531675645095245491150949345727938441185910660013772325360518530732512",
"owner": "0x37007a1c233f00b423bc0d177ac5b50ca9417596",
"expiry": "perpetual", "perpetual": true, "version": 0,
"resolver": "0x66ae037d2a6a770b4772b889b6ca1704504399f2", "reserved": false,
"registeredBlock": 94344647, "updatedBlock": 94348476, "manifest": "https://agts.dev/demoagent.json"
}, …]
}expiry is "perpetual" or unix seconds as a string. 400 for a malformed address; 503 if the index is unavailable. Response is CDN-cached for 60 s.
GET /api/v2/allowlist Live
Rate limit: 30 per minute
The migration allowlist. With address alone: every entry for that wallet (label + Merkle proof). With label and address: the single proof the proof-migration path submits on chain.
curl "https://agtnames.com/api/v2/allowlist?address=0x37007a1c233f00b423bc0d177ac5b50ca9417596"{
"root": "0x023d33575f28762f0b36a479f49df30c3cfe8c71009e5644288bcdd1b062b9d3",
"claimant": "0x37007a1c233f00b423bc0d177ac5b50ca9417596",
"entries": [
{ "label": "123456789", "proof": ["0x956c7eaf…2616", "0x714ca5c8…5c5e", "…"] },
…
]
}404 when the wallet (or pair) is not on the list; 503 until an allowlist is published.
POST /api/v2/zone-claim/challenge Live
Rate limit: 20 per minute
Migration path 3, for names that exist as zones but were never minted: start a zone-owner challenge and get the TXT record to add. Stateless — the code is derived from the label and wallet and is valid for three days.
curl -X POST https://agtnames.com/api/v2/zone-claim/challenge \
-H "content-type: application/json" \
-d '{"label":"exampleagent","wallet":"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"}'{
"label": "exampleagent.agt",
"wallet": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
"code": "9319cad50d4b6de6",
"record": { "type": "TXT", "name": "@", "value": "agt-claim=9319cad50d4b6de6" },
"validForDays": 3,
"instructions": [ "…add the TXT record…", "…then verify…", "…then migrate on /migrate with this wallet." ]
}POST /api/v2/zone-claim/verify Live
Rate limit: 10 per minute
Check the TXT record. On success the label and wallet are queued for the next allowlist publication.
curl -X POST https://agtnames.com/api/v2/zone-claim/verify \
-H "content-type: application/json" \
-d '{"label":"exampleagent","wallet":"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"}'200 { "verified": true, "method": "zone-txt", "next": "…" }
404 { "error": "zone does not exist" }
409 { "verified": false, "error": "TXT record not found or does not match", "txtSeen": ["…"] }
503 { "error": "resolver unreachable, try again" }GET /api/v2/zone-claim/mine Live
Rate limit: 30 per minute
curl "https://agtnames.com/api/v2/zone-claim/mine?wallet=0x37007a1c233f00b423bc0d177ac5b50ca9417596"{ "wallet": "0x37007a1c233f00b423bc0d177ac5b50ca9417596", "claims": [] }
// each claim: { "label", "method": "zone-txt" | "minted-owner", "verifiedAt", "published": boolean }POST /api/notify Live
Rate limit: 5 per minute
Register interest in a name while registration is closed. Idempotent per email and label; the email is never returned by any route.
curl -X POST https://agtnames.com/api/notify \
-H "content-type: application/json" \
-d '{"email":"you@example.com","label":"exampleagent"}'{ "success": true, "created": true } // "created": false on a repeatManifest
POST /api/v2/manifest/pin Live
Rate limit: 10 per minute
Pin a signed v3 manifest whose signer is the name's current on-chain owner. The server never signs; it only refuses documents that would fail verification. The response uri is what the owner then writes to the resolver with setAgentManifest (the /manifest editor does this in one transaction).
curl -X POST https://agtnames.com/api/v2/manifest/pin \
-H "content-type: application/json" \
-d @signed-manifest.json # { "manifest": { "agt": "3.0", "name": "you.agt", "owner": "0x…", …, "signature": "0x…" } }200 { "uri": "ipfs://bafkrei…", "cid": "bafkrei…", "provider": "pinata", "label": "you", "owner": "0x…" }
400 { "error": "Expected a signed Manifest v3 with agt=3.0 and name=<label>.agt" }
409 { "error": "Manifest does not verify against the on-chain owner", "reasons": ["signer 0x… != owner 0x…"] }
413 { "error": "manifest exceeds 65536 bytes" }
502 { "error": "Pinning failed; try again shortly" }Registration
POST /api/checkout Closed until Stage 4
Rate limit: 5 per minute
Card checkout for a new name (Stripe Checkout with server-side price verification). Body when open: { domain, walletAddress, email?, termsAccepted, years } → { success, url }.
503 { "success": false, "error": "Registration opens soon. Leave your email on the register page and we will tell you when it does.", "registrationOpen": false }POST /api/v2/quote Closed until Stage 4
Rate limit: 20 per minute
An EIP-712 registration or renewal quote for the on-chain checkout path. Body when open: { label, to, years = 1, payToken: "usdc" | "native", renew? } → the signed quote, signature and the controller method to call (register(Quote,bytes) or renew(Quote,bytes)).
404 { "error": "Registry v2 checkout is not enabled" }GET /api/checkout/status Live
Poll fulfillment after a card payment. Param: session_id. Returns fulfillment_status, domain, walletAddress, txHash, mint_after.
GET /api/claim/status Legacy name
Mint status for a name on the registry. The route keeps its original name; in current vocabulary this reports a registration or migration mint.
curl "https://agtnames.com/api/claim/status?domain=launchpad.agt"{
"success": true, "status": "COMPLETE", "transactionHash": null,
"tokenId": "74213674913414793103689332001647165694612910724881941644579943946836492950816",
"contract": "0x5B9386C47395B0551c814cC03b69cbD20eb0C87A", "registry": "v2",
"owner": "0x37007A1C233F00b423BC0d177AC5B50CA9417596"
}status is COMPLETE, PENDING, CANCELLED, FAILED or UNKNOWN.
Feeds and machine access
Beyond the JSON routes, the site publishes the same public data in the formats readers, aggregators and agents already consume. None of these need a key.
GET /activity/feed.xmlandGET /activity/feed.json: the newest 100 activity rows as Atom and JSON Feed 1.1. Each item links to the name page; ids reuse the activity log's dedupe key so a re-indexed event never repeats.GET /capabilities/<id>/feed.xml: the verified agents publishing one capability, as Atom.GET /.well-known/agt.json: the registry described for machines: chain, contract addresses, API routes, feeds, install commands, the spec URL.GET /llms.txtandGET /llms-full.txt: a plain-text map of the docs, and the same plus the manifest specification and the full capability vocabulary.GET /sitemap.xml: every docs, capability and name page; a name'slastmodis its newest activity row.
Pages carry schema.org JSON-LD (Dataset on the directory and activity, DefinedTermSet on the capability vocabulary, SoftwareApplication on the packages and on names with published records).
Not public
/api/admin/* requires Authorization: Bearer <ADMIN_API_KEY>; /api/cron/* is called by the scheduler with a shared secret; /api/webhooks/stripe accepts Stripe-signed events only. None of them are part of the public surface.
See also
- Quick start — the same lookups from the SDK, CLI, an MCP client or raw JSON-RPC.
- Records & Resolution — the on-chain data these routes read.
- Migrating to v2 — how the allowlist and zone-claim routes fit the three migration paths.