Onboarding with APIs.io

APIs.io publishes a machine-readable API Onboarding Descriptor at /.well-known/api-onboarding. It declares what it takes to get from a cold start to an authorized call here — the doors, the tiers, the credential shapes, and the places where the door is still shut.

This page is its human twin. Same facts, same gaps, in prose. If the two ever disagree, the descriptor is the one a machine reads, and the disagreement is a bug — tell us.

The path, end to end

Four steps. Step 1 works right now with nothing in your hands; steps 2 and 3 are where the callers diverge; step 4 is the same for everyone.

  1. 1 Everyone · no account, no key, no form

    Discover, keyless

    Prove the door is open with one unauthenticated call. Keyless reaches search, providers, APIs, tags, industries and the artifact collections.

    HTTP no auth AOD flow.steps.probe

  2. 2 Choose by what you are, not by rank

    Pick your door

    Five registration mechanisms are declared, and they are not a ladder you climb in order — they are different callers. A human in a browser, a client registering an OAuth client, and an agent with nobody in the loop each take a different one.

    open browser-oauth dcr cimd aauth

  3. 3 Where the doors differ

    Take a credential

    An API key on a browser sign-in, an OAuth client plus an authorization-code + PKCE token, or — for a signing agent — an agent principal with its own key and quota minted by a client-credentials call. Nothing here is one-time-display; keys are rotatable.

    API key · X-API-Key OAuth 2.0 + PKCE RFC 7591 DCR CIMD RFC 9421 · Ed25519

  4. 4 Everyone · same wire, same meters

    Call it, and read your own budget

    Send the credential, then read the limits off the response rather than guessing them. Tiers gate resources: above your tier is 402, over your meter is 429, and it is never a 403 for either.

    RateLimit-Policy X-RateLimit-Tier MCP · same tiering

Step 1, in full

Discovery needs no account, no key and no form. Prove it in one call:

curl "https://apis.io/api/v1/search?q=sms"

Keyless reaches search, providers, APIs, tags, industries and the artifact collections. It is not the whole API — ratings, capabilities, cohorts, insights, resolve, enrich, the playground list and the service root are paid, and answer 402.

Do not probe the service root to test the door. GET /api/v1/ is itself gated and returns 402, so probing it proves the opposite of what you were asking.

Which door is yours?

A person, with a browser

browser-oauth

Sign in with GitHub, Google or LinkedIn. This is also the only door that reaches a paid tier.

You walk away with an API key.
A client app or MCP client

dcr / cimd

Register an OAuth client dynamically, or skip registration with a client_id that is a URL. The authorize step still renders consent to a logged-in human.

You walk away with an OAuth client.
An agent, no human at any step

aauth

Sign each request with your own Ed25519 key and present an aa-agent+jwt from an agent provider we allowlist.

You walk away with an agent principal — its own key and quota.

Or take none of them: open is a door too, and it is the one that is already unlocked.

The five doors

MechanismWho it is forTechnologyWhat you walk away with
open anyone, including an agent, right now plain HTTP, no auth nothing to hold — keyless access to the catalog
browser-oauth a human with a browser GitHub / Google / LinkedIn sign-in → X-API-Key an API key
dcr a client that wants an OAuth registration RFC 7591 + authorization code & PKCE an OAuth client for the MCP surface
cimd a client whose client_id is a URL Client ID Metadata Document — no registration call an OAuth client
aauth an agent, with no human at any step RFC 9421 Ed25519 signing + aa-agent+jwt an agent principal with its own key and quota

open — no registration

Nothing to do. Call it.

browser-oauth — the human door

Sign in at apis.io/developer/account with GitHub, Google or LinkedIn. A Learn key is issued free on sign-in; Understanding and Influence are self-serve from the same page. Send the key as an X-API-Key header:

curl -H "X-API-Key: <your key>" "https://apis.io/api/v1/industries"

Rotate or revoke from the account page. There is no key-management endpoint in v1.

dcr and cimd — registering an OAuth client

The authorization server has supported both all along. Register through POST https://apis.io/api/v1/auth/register, or skip registration entirely with a Client ID Metadata Document. Either way you then run authorization-code + PKCE against /api/v1/auth/authorize and /api/v1/auth/token, scopes apis:read and apis:pro. See /.well-known/oauth-authorization-server.

The authorize step renders a consent page against a logged-in session, so a human is present for this one — which is exactly the gap the next door exists to close.

aauth — no registration, and no human

An agent signs its request with its own key (RFC 9421, Ed25519) and presents an aa-agent+jwt in which its agent provider vouches for its aauth:local@domain identifier. We verify both and recognise a caller we have never seen.

Signing alone earns attribution — the caller is recognised and audited as its identifier — but no meter of its own: until it takes a principal it is limited per IP like any anonymous caller. To hold an account, POST grant_type=client_credentials to the token endpoint with that same signature. It mints an agent principal with its own API key and quota, a scope ceiling of apis:read, no refresh token, and no way to self-grant paid data.

Anonymous callers are refused, and that is the point: the identifier costs an allowlisted agent provider vouching for you, and an account that costs nothing to mint makes reputation over it worthless. Reversible in one request — DELETE /api/v1/auth/me.

A bodied request must sign a content-digest; GET and HEAD need none. Resource metadata lives at /.well-known/aauth-resource.json. The protocol is draft-hardt-oauth-aauth-protocol.

This door is the one thing the descriptor states as a requirement. An allowlisted agent provider vouching for your aauth:local@domain identifier is what establishes domain control, so the onboarding descriptor declares it in the format’s own words rather than leaving you to infer it from a rejection:

"verification": [
  { "facet": "domain_control", "min_grade": "verified", "blocking": true,
    "vocabulary": "https://apis.io/kya/" }
]

min_grade is a floor, not an equality — a consumer holding verified satisfies a requirement of attested. The other four doors declare nothing, because they require nothing: open, browser-oauth, dcr and cimd are unaffected by this.

The technology it runs on

Nothing here is bespoke. Every step above is an open specification, and every one of them is declared at a well-known path a machine can read before it ever talks to us.

TechnologyWhat it does hereWhere it is declared
API Onboarding Descriptor 0.1 Declares this entire page in machine-readable form — mechanisms, plans, credential shapes, the probe step, the economics, and the gaps. /.well-known/api-onboarding
API key over a header The credential a browser sign-in issues, and the one an agent principal holds. Sent as X-API-Key; also read from APIS_IO_API_KEY. Authentication docs
OAuth 2.0 — authorization code + PKCE /api/v1/auth/authorize and /api/v1/auth/token, scopes apis:read and apis:pro. Grants: authorization code, refresh token, client credentials. /.well-known/oauth-authorization-server
RFC 7591 — Dynamic Client Registration Registers an OAuth client with no human, at POST /api/v1/auth/register. Authorization server metadata
Client ID Metadata Documents Lets a client whose client_id is a URL skip registration altogether. Authorization server metadata
RFC 9421 — HTTP Message Signatures Ed25519 request signing over at least @method, @path, @authority and signature-key. A bodied request also signs a content-digest. /.well-known/http-message-signatures-directory
AAuth — draft-hardt-oauth-aauth-protocol Carries agent identity: an aa-agent+jwt in which an allowlisted agent provider vouches for an aauth:local@domain identifier. /.well-known/aauth-resource.json
KYA — Kin Score, Consumer 0.1 The vocabulary the requirement above is written in: six facets, 26 checks, and four grades (verified, attested, declared, absent). Two numbers, never one — disclosure is what you told us, verification is what we confirmed. Graded facts, never a trust verdict. /kya/ · the API is deployed dark
RateLimit header fields Every response states its own policy, limit, window and tier, so a caller reads its budget instead of guessing it. On every response — see below
Model Context Protocol The same catalog as an MCP server, on the same tiering and the same credentials. /.well-known/mcp/server-card.json

What each tier reaches

Tiers gate resources, not scopes. The full matrix is on the plans page, and that page is the source of truth — the boundary moves.

PlanTier on the wirePriceRateDaily quota
Explorefree$05 req/s500
Learnstarter$020 req/s2,000
Understandingpro$199/mo100 req/s10,000
Influencebusiness$499/mo400 req/s25,000

The plans are named for what you are doing with the catalog; the API still identifies them by their original short names, and will keep doing so. The wire name is what you get in X-RateLimit-Tier, in every 402 body, and in the x-tier extension on every operation in the reference — so if you are reading a response rather than a page, that is the mapping you need.

A caller sending no key at all gets Explore access but no usage plan: it is limited per IP at the edge (3,000 requests / 5 minutes), because a plan meters a key and every anonymous caller would have to share one. Your limit does not move with anyone else’s traffic.

Read your own budget, don’t guess it

Every response carries its own limits:

ratelimit-policy: "quota";q=500;w=86400, "burst";q=5;w=1
x-ratelimit-tier: free
x-ratelimit-limit: 500
x-ratelimit-window: 86400

Two failures that are not the same failure

It is never a 403 for either.

The MCP server

https://apis.io/mcp shares exactly the same tiering. Searching the catalog, reading a provider or an API, and browsing tags, taxonomy and artifacts are free and need no key. Anything that synthesises across the catalog needs Understanding; benchmarking, comparison, gap analysis, bulk export and requesting a check need Influence.

What is still shut

The descriptor carries these in its gaps array, and they belong on the human page too.

Only a paid tier still requires a human. An agent can go from cold discovery to an authorized call with nobody in the loop — sign with AAuth, take a principal, hold a key and a quota. What it cannot do is buy anything: the scope ceiling for an agent principal is apis:read, and paid data answers 402. Machine payment is a separate problem and is deliberately not solved here. (roadmap#105)

The aauth allowlist has exactly one agent provider in it, and we run it. A probe of 1,486 hosts on 2026-08-30 found no other AAuth resource document anywhere in the catalog. Read this as a worked example, not an interoperating ecosystem.

maturity reads self-serve because that is the highest rung the AOD 0.1 enum has. It does not distinguish a stranger with a browser from a stranger with no human at all, and those are now two different doors here. (roadmap#117)

A consumer cannot yet read its own record here. The descriptor’s verification[] block is no longer empty — it states the one thing apis.io actually demands of a caller, domain_control at grade verified, which is the requirement the aauth door has enforced all along and had no machine-readable place to say. What is still shut is the other half: /api/v1/kya/me and /api/v1/agents/{sub} are built and deployed dark, and answer 404 until the surface is switched on. So a caller can learn what is demanded of it and cannot yet check whether it holds it. Stating the requirement first is deliberate — claiming the record exists before it answers would be the worse order. (roadmap#110, #112)

Publish your own

The descriptor is a small file at a well-known path, and it is the piece nothing else covers — OpenAPI describes what your API does, OAuth and DCR describe the credential handshake, and neither says what it takes to get there: the account, the plan gate, the terms, the verification queue, and the console a human still has to click through.

Read the spec and schema at apicommons.org/onboarding, then serve yours at /.well-known/api-onboarding. APIs.io reads it — add your API and the probe looks for your APIs.json, your onboarding descriptor, your OpenAPI, your llms.txt and your MCP endpoint before it asks you to fill in anything.

Ours is at /.well-known/api-onboarding. Copy it, argue with it, or tell us where it is wrong at github.com/api-search/apis-io.