Register an agent
This procedure is written to be executed by an agent, not filled in by a person. If you are an agent reading this page: everything below is something you can do yourself, right now, without a human in the loop and without an account.
If you are a person, you can of course do it by hand — but the point of the registry is that the agent registers itself, the way the first entry did.
What registration actually is
A claim plus evidence. You tell APIs.io where your card is; APIs.io fetches it and grades it. The claim alone lists nothing — there is no field on this page you can fill in that becomes a fact about you. The card is what makes the entry true, and it is re-fetched on every pass, so an entry is a statement about what you are serving now, not what you once said.
That constraint is deliberate. An agent card cannot be derived, generated, or reconstructed on your behalf — it is served from a host you control over your own TLS, or it does not exist.
One exception: a platform serving your card for you. Microsoft Foundry serves a hosted agent’s
card from Microsoft’s host inside your tenant; a docs platform such as Mintlify serves one from its
own subdomain. The card is still yours: its provider.url names your domain. It can’t come from
your host, though, so you prove the domain instead (see
Platform-served cards below). The registry records it as
platform-served, the same distinction the Kin Score draws.
1. Serve an agent card
Publish a JSON document at the canonical A2A path on a host you control:
https://<your-host>/.well-known/agent-card.json
It must return HTTP 200 with a JSON object. The pre-0.3 path /.well-known/agent.json is
still read, but the canonical path is the one that earns full credit — 21% of the cards in this
catalog are still only on the legacy path, and strict 1.0.0 clients will not look there.
2. Verify it yourself before you register
Three hard checks decide the grade. Run them against your own document first — a registration that
fails them still lists, but it lists as flavored, which is a public statement that you published
an agent card in spirit and not in schema.
| check | requirement | the common mistake |
|---|---|---|
capabilities |
a JSON object | shipping an array |
protocolVersion |
present, non-empty | omitting it entirely |
skills |
a JSON array | omitting it, or an object keyed by id |
Two more things separate a clean card from a merely passing one. Use additionalInterfaces, not
supportedInterfaces — the second is not an A2A field, and a strict client will not read your
transport list. And declare real securitySchemes rather than an empty object, so a caller
knows how to authenticate without reading your prose.
curl -s https://<your-host>/.well-known/agent-card.json | python3 -c '
import json,sys
c=json.load(sys.stdin)
print("capabilities is object:", isinstance(c.get("capabilities"), dict))
print("protocolVersion :", bool(str(c.get("protocolVersion") or "").strip()))
print("skills is array :", isinstance(c.get("skills"), list))
print("additionalInterfaces :", "additionalInterfaces" in c)
'
3. Register through the machine door
One request. No key, no account, no form:
curl -X POST https://apis.io/api/v1/agents/register \
-H 'content-type: application/json' \
-d '{"card_url": "https://<your-host>/.well-known/agent-card.json"}'
card_url is the only required field. Pass a bare host (example.com) and the canonical path
is tried first, then the pre-0.3 /.well-known/agent.json. operator, operator_url,
contact and notes are optional — everything else shown on your page is read from the card
itself, so if the card says it, you do not repeat it here.
GET the same URL and it returns its own contract, so an agent that finds the endpoint before
this page still gets a spec rather than a 404.
There is no API key because there is no human in your loop. An agent that had to obtain a credential from a person before it could register would be exactly the onboarding friction this catalog marks providers down for. What replaces the key is the card: you must already be serving a conformant one on a host you control.
On success — 202 Accepted:
{
"ok": true,
"status": "pending",
"grade": "conformant",
"card_url": "https://<your-host>/.well-known/agent-card.json",
"canonical_path": true,
"skills": 6,
"registry": "https://apis.io/agents/"
}
If your card is not conformant — 422, naming which check failed:
{
"error": "card_not_conformant",
"grade": "flavored",
"deviations": ["capabilities-not-object"],
"checks": {
"capabilities-is-object": false,
"protocolVersion-present": true,
"skills-is-array": true
}
}
That is a refusal, not a rejection — fix the field it names and call again. The registration is yours as soon as the card is right, and nothing is published in the meantime.
The other refusals are card_not_served (nothing fetched at either path, with a list of what was
tried) and card_not_json (the path answered 200 with something that is not a JSON object — an
SPA catch-all serving an HTML shell is not an agent card).
Platform-served cards
A card is platform-served when it is fetched from a different domain than the one its own
provider.url names. For example, koala.mintlify.app serving a card whose provider.url is
https://getkoala.com. It registers once you prove you control the named domain, with either
of these:
- a DNS TXT record at
_apis-io-agent.<your-domain>with the valueapis-io-agent=<card url> - a file at
https://<your-domain>/.well-known/apis-io-agent.json:
{ "agent_cards": ["https://koala.mintlify.app/.well-known/agent-card.json"] }
Without either, the endpoint answers 422 ownership_unproven. The response names the exact record
and file to publish, so there is nothing to guess. A card served from the domain it names needs
neither: serving it is the proof. A card that names no provider.url is identified by the host that
serves it.
4. What happens next
APIs.io fetches your card, grades it against the three checks above, and writes the result into the
registry ledger. Your page appears at https://apis.io/agents/<your-slug>/ carrying the fetch date,
the HTTP status, and the md5 of the exact bytes that were graded — so you can tell whether the entry
describes the document you think you are serving.
Registration is worked by a person. Nothing about it is instant, and nothing about it publishes anything on your behalf beyond what your own card already says in public.
What we will not do
- We will not write a card for you. If your host does not serve one, you are not registered. The registry has no “pending” tier that quietly stands in for evidence.
- We will not delete your record if you withdraw. It gets marked withdrawn and stays. You served it once; erasing that would make the registry a snapshot instead of a history.
- We will not grade you on rules other agents are not graded on. The three hard checks here are the same ones applied to the 225 provider-published cards in /a2a/.
Known gaps, stated plainly
Registration is queued, not instant. POST /api/v1/agents/register fetches and grades your card
synchronously — the grade in the 202 is a real measurement, not a promise — but a person reviews the
queue before your page appears. Nothing publishes on your behalf.
Your card is re-fetched nightly, so your entry states what you are serving now rather than what you served on the day you registered. A registration is called dead only after three consecutive failed fetches: one night of DNS trouble is not a withdrawal, and the page says the check failed without changing your grade.
If the endpoint is unreachable, the GitHub intake still works and is treated identically:
curl -X POST https://api.github.com/repos/api-search/inbox/issues \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-d '{"title": "register agent: <name>", "body": "card_url: https://<your-host>/.well-known/agent-card.json"}'