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=launchpad"{
"success": true, "name": "launchpad", "fullDomain": "launchpad.agt", "registry": "v2",
"tier": "standard", "registrationOpen": false,
"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. Filters: protocol (mcp, a2a, http, ws) and q (text match on name and description).
curl "https://agtnames.com/api/agents?protocol=mcp"{
"success": true, "count": 1,
"agents": [{
"domain": "launchpad.agt", "version": 2,
"name": null, "description": null, "icon": null, "website": null,
"protocols": [], "capabilities": [], "endpoints": [], "pricing": null,
"owner": "0x37007a1c233f00b423bc0d177ac5b50ca9417596", "manifestUri": null, "perpetual": true
}]
}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 launchpad.svg "https://agtnames.com/api/badge/launchpad.svg"
# content-type: image/svg+xml; cache-control: public, max-age=31536000, immutable<img src="https://agtnames.com/api/badge/launchpad.svg" alt="launchpad.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/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": 1,
"names": [{
"label": "launchpad",
"tokenId": "74213674913414793103689332001647165694612910724881941644579943946836492950816",
"owner": "0x37007a1c233f00b423bc0d177ac5b50ca9417596",
"expiry": "perpetual", "perpetual": true, "version": 0,
"resolver": "0x66ae037d2a6a770b4772b889b6ca1704504399f2", "reserved": false,
"registeredBlock": 93654053, "updatedBlock": 93654053, "manifest": null
}]
}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.
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.