Skip to content
SeenLens

agent-card.json and other .well-known agent files: how to fix them

Five files under /.well-known/ describe services to agents: api-catalog, oauth-protected-resource, oauth-authorization-server, agent-card.json and ucp. Publish a file only if you run the matching service. If you do not, a real 404 is correct, and SeenLens marks the check not applicable. SeenLens flags a file that exists but is wrong, or an HTML page that stands in for it.

By SeenLens · Last updated

Run the free 43-check scan on your page

Do I need any of these files?

Most sites need none of them. Each file describes a service that you operate: a public API, an OAuth protected API, an OAuth server, an A2A agent or a shopping profile for agents. A blog, a company site or a store with a normal checkout can skip all five.

When you skip a file, return a real 404 for its path. Do not publish an empty file or a placeholder to make a check green. A page that answers the path with HTML and status 200 is a soft 404, and SeenLens flags that. See soft 404 pages.

The standards differ in maturity. RFC 9727, RFC 9728 and RFC 8414 are published IETF standards. The A2A agent card comes from the A2A protocol specification, which lists version 1.0.0 as its latest release. The UCP profile comes from the Universal Commerce Protocol specification, whose pages carry date versions such as 2026-04-08. No study shows that these files change AI search visibility.

How does SeenLens test these files?

SeenLens requests each path once. All five checks use the same rules.

Result of a /.well-known file check
What SeenLens findsResult
404, or any non-200 answerNot applicable
200 with an HTML pageWarn. The path is a soft 404.
200 with a body that is not valid JSONFail
200 with JSON nested more than a safe depthFail
200, valid JSON, but the wrong content typeWarn
200, valid JSON and the right content typePass

The expected content type is application/linkset+json for the API catalog. For the other four files, the content type must contain json. SeenLens does not validate the fields inside the document, so check those against the standard.

Terminal
curl -sI https://example.com/.well-known/api-catalog
curl -sI https://example.com/.well-known/agent-card.json

API Catalog: /.well-known/api-catalog

RFC 9727 (June 2025, Standards Track) defines the well known URI /.well-known/api-catalog. It lets a client find a publisher's APIs, with their descriptions and documentation. The catalog uses the Linkset format (RFC 9264) and the media type application/linkset+json. The RFC asks for a profile parameter of https://www.rfc-editor.org/info/rfc9727.

Publish it only if you run public APIs. A minimal catalog for one API looks like this.

/.well-known/api-catalog
{
  "linkset": [
    {
      "anchor": "https://api.example.com/v1",
      "service-desc": [{ "href": "https://api.example.com/openapi.json", "type": "application/json" }],
      "service-doc": [{ "href": "https://example.com/docs/api", "type": "text/html" }]
    }
  ]
}

Send it as Content-Type: application/linkset+json; profile="https://www.rfc-editor.org/info/rfc9727". Set the type yourself (see the section on content types below).

OAuth Protected Resource Metadata: /.well-known/oauth-protected-resource

RFC 9728 (April 2025, Standards Track) lets an API tell OAuth clients how to use it. The only required field is resource, the identifier of the protected resource. It must match the URL used to fetch the metadata. authorization_servers, scopes_supported and bearer_methods_supported are optional or recommended. The content type is application/json.

If the resource identifier has a path, such as https://example.com/api, the well known string goes between the host and the path: /.well-known/oauth-protected-resource/api. A protected resource can also point clients to the file with the resource_metadata parameter in a WWW-Authenticate header.

/.well-known/oauth-protected-resource
{
  "resource": "https://example.com",
  "authorization_servers": ["https://auth.example.com"],
  "scopes_supported": ["read", "write"],
  "bearer_methods_supported": ["header"]
}

Publish it only if you run an OAuth protected API. A site with a login form for its own pages does not need it.

OAuth Authorization Server Metadata: /.well-known/oauth-authorization-server

RFC 8414 (June 2018, Standards Track) publishes the endpoints of an OAuth server. The required fields are issuer (an HTTPS URL without query or fragment) and response_types_supported. authorization_endpoint is required unless no grant type uses it, and token_endpoint is required unless only the implicit grant is supported. The issuer value must exactly match the issuer used to build the request URL, or clients must discard the data. If the issuer has a path, the well known string goes before the path.

Publish it only if you operate an OAuth server on this domain. A site that signs users in through a provider does not run one. Do not copy another provider's metadata to your domain.

A2A agent card: /.well-known/agent-card.json

The A2A protocol uses an agent card to describe an agent: identity, capabilities, skills, service endpoint and authentication. The specification gives the discovery path as https://{server_domain}/.well-known/agent-card.json. Version 1.0.0 is the latest release the A2A site lists.

The spec marks these top level fields as required: name, description, supportedInterfaces, version, capabilities, defaultInputModes, defaultOutputModes and skills. Optional fields include provider, documentationUrl, securitySchemes, securityRequirements, signatures and iconUrl. Servers should send Cache-Control with a max-age and an ETag. Start from the sample card in section 8.5 of the specification.

Publish it only if you run an A2A agent that other agents call. A chat widget on your site is not an A2A agent.

UCP commerce profile: /.well-known/ucp

The Universal Commerce Protocol (UCP) lets shopping agents learn how to buy from a business. A business publishes a JSON profile at /.well-known/ucp. In the version dated 2026-04-08, the profile is a JSON object with a required ucp member. ucp.version, ucp.services and ucp.payment_handlers are required, and the last two must be present even if empty. The spec requires HTTPS, no redirects, and Cache-Control: public with a max-age of at least 60 seconds.

Publish it only if you take part in agent checkout. Read the current UCP specification first, because it changes by date version.

How do I serve these files with the right content type?

A file without a .json extension, such as api-catalog, may get a generic content type. Set it yourself.

nginx.conf
location = /.well-known/api-catalog {
    default_type application/linkset+json;
}
location = /.well-known/agent-card.json {
    default_type application/json;
    add_header Cache-Control "public, max-age=300";
}

In Next.js, put JSON files with an extension in public/.well-known/. For a path without an extension, use a route handler such as app/.well-known/api-catalog/route.ts that returns the JSON with the header Content-Type: application/linkset+json. On WordPress, upload the files to a .well-known folder in the site root. A Shopify store cannot place files at /.well-known/ paths without a proxy, so skip these checks there.

How do I verify the fix?

  1. Run curl -sI for each file you publish. The status must be 200 and the content type must match the table above.
  2. Run curl -s URL | python3 -m json.tool. The JSON must print.
  3. For each file you do not publish, run curl -sI and confirm a 404.
  4. Scan the page with SeenLens. Published files show pass, and missing files show not applicable.

When can I ignore these checks?

Ignore them when you do not run the service. SeenLens gives a 404 the result 'not applicable', which leaves the check out of the score and lists it as not tested. Each of the five checks has weight 1 in the agent readiness dimension. Spend the time on the checks that affect every visitor first.

Scan your page with SeenLens

Sources