Yappy API authentication

Most of this API needs no credentials. Every read endpoint under /api/v1, and both MCP servers, are open. Start there and only come back to this page if you hit a rate ceiling.

Discovery first

An agent should not guess. The two metadata documents describe everything:

DocumentURL
Protected resource metadata (RFC 9728)[/.well-known/oauth-protected-resource](https://yappy.biz/.well-known/oauth-protected-resource)
Authorization server metadata (RFC 8414)[/.well-known/oauth-authorization-server](https://yappy.biz/.well-known/oauth-authorization-server)
Prose walkthrough for agents[/auth.md](https://yappy.biz/auth.md)

Probing https://yappy.biz/agent/auth returns a 401 whose WWW-Authenticate: Bearer resource_metadata="…" header points at the first of those, so one request is enough to learn the rules.

Register a client

RFC 7591 dynamic client registration, no human in the loop:

curl -sX POST https://yappy.biz/oauth/register \
  -H 'content-type: application/json' \
  -d '{
    "client_name": "my-agent",
    "grant_types": ["client_credentials", "authorization_code"],
    "response_types": ["code"],
    "redirect_uris": ["https://example.com/callback"],
    "token_endpoint_auth_method": "client_secret_basic",
    "scope": "read:releases read:docs read:pricing"
  }'

The response carries client_id, client_secret, and the issued scopes. Store the secret; it is not retrievable afterwards.

Get a token

Machine-to-machine, which is what an agent wants:

curl -sX POST https://yappy.biz/oauth/token \
  -H 'content-type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials&client_id=…&client_secret=…&scope=read:releases'

Authorization code with PKCE S256 is also supported, for the case where a token should be tied to a person rather than a program:

GET /oauth/authorize
  ?response_type=code
  &client_id=…
  &redirect_uri=https://example.com/callback
  &scope=read:docs
  &state=…
  &code_challenge=…
  &code_challenge_method=S256

S256 is the only challenge method accepted. Plain is refused.

Scopes

Least privilege is machine-readable — the same list appears in scopes_supported in the protected-resource metadata and in the OpenAPI security schemes.

ScopeGrants
read:releasesRelease history and the current version
read:docsDocumentation pages and search
read:pricingPricing and plan data
read:faqFrequently asked questions
export:docsStarting and polling export jobs

Ask for the narrowest set that does the job. A token with no scope still reads everything that is public — the scopes exist to raise limits and to gate exports, not to unlock secrets.

Use the credential

curl -s https://yappy.biz/api/v1/releases \
  -H 'Authorization: Bearer <access_token>'

Bearer in the Authorization header is the only accepted method — no query parameter, no cookie. Tokens are opaque, expire in one hour, and carry the scopes they were issued with.

Errors

401 with WWW-Authenticate: Bearer error="invalid_token" means expired or malformed — get a new one. 403 with error="insufficient_scope" names the scope you needed in the header. Both bodies are RFC 9457 problem documents; see errors.

Revocation

RFC 7009:

curl -sX POST https://yappy.biz/oauth/revoke \
  -H 'content-type: application/x-www-form-urlencoded' \
  -d 'token=<access_token>&client_id=…&client_secret=…'

Returns 200 whether or not the token existed, as the RFC requires. Revoking a client's secret revokes every token issued under it.

Reading this as an agent? The same page in markdown: /developers/authentication.md · machine index: /llms.txt · API: /openapi.json · MCP: https://yappy.biz/mcp