AdCP discovery files

adagents.json is the file a publisher or data provider hosts at /.well-known/adagents.json to declare which agents may sell its inventory or resell its signals; brand.json, at /.well-known/brand.json, is the buy-side half.

Publisher domains host an adagents.json for their properties, data provider domains host one for their signals, and brands host brand.json. The consumer is a buyer's agent checking that whoever offered it the inventory is allowed to sell it, which is why the declaration sits on the domain that owns the thing rather than in the offer.

The ads.txt and sellers.json equivalents

The mapping is AdCP's own: adagents.json takes the ads.txt role, and brand.json's properties take the sellers.json role, each property carrying a relationship. direct, delegated and ad_network appear on both sides with the same meaning.

Where the two files sit in the registry

AdCP, the Ad Context Protocol, is governed by AgenticAdvertising.org and ships as one versioned schema registry. 2 schemas in it carry a file_location: the annotation marking a document that is fetched from a fixed path on a domain rather than passed inside an API call. Those two are adagents.json, hosted by the owner of the inventory or the data, and brand.json, hosted by the owner of the brand.

AdCP names three further well-known paths that have no schema in the registry, all three specified in prose only: /.well-known/jwks.json, which publishes an agent's own signing keys and which the signing_keys pin overrides; /.well-known/adcp-ownership.txt, which carries the ownership challenge; and /.well-known/governance-revocations.json. Verification rules for those three paths are prose and have no schema in the registry.

adagents.json

Declaration of authorized agents for advertising inventory and data signals.

Fetched from https://<domain>/.well-known/adagents.json

The 2 branches of adagents.json

Variant 1

URL reference variant - points to the authoritative location of the adagents.json file

adagents.json — Variant 1 — 3 fields, 1 required
FieldTypeRequiredDescription
$schemastringJSON Schema identifier for this adagents.json file
authoritative_locationstringrequiredHTTPS URL of the authoritative adagents.json file.
last_updatedstringISO 8601 timestamp indicating when this reference was last updated

Variant 2

Inline structure variant - contains full agent authorization data

adagents.json — Variant 2 — 16 fields, 1 required
FieldTypeRequiredDescription
$schemastringJSON Schema identifier for this adagents.json file
contactobjectContact information for the entity managing this adagents.json file (may be publisher or third-party operator)
catalog_etagstringOpaque publisher-controlled cache validator for the public catalog portions of this file (`properties[]`, `collections[]`, `placements[]`, `formats[]`, `signals[]`, and tag metadata).
propertiesproperty[]Array of all properties covered by this adagents.json file.
revoked_publisher_domainsobject[]Publisher domains explicitly removed from this managed network.
collectionscollection[]Collections produced or distributed by this publisher.
placementsplacement-definition[]Canonical placement definitions for properties in this file.
formatsany[]Publisher-authoritative format catalog.
superseded_bystringOptional pointer indicating this adagents.json file has been superseded by another adagents.json at a different URL.
tagsobjectMetadata for each tag referenced by properties.
placement_tagsobjectMetadata for each tag referenced by placements.
authorized_agentsany[]requiredArray of sales agents authorized to make inventory from this file available to buyers.
last_updatedstringISO 8601 timestamp indicating when this file was last updated
property_featuresobject[][AdCP 3.0] Optional list of agents that provide property feature data (certifications, scores, compliance status).
signalssignal-definition[]Signal definitions published by this domain.
signal_tagsobjectMetadata for each tag referenced by signals.
adagents.json example 1 — source
{
  "$schema": "/schemas/3.1.13/adagents.json",
  "authoritative_location": "https://cdn.example.com/adagents/v2/adagents.json",
  "last_updated": "2025-01-15T10:00:00Z"
}

brand.json

Brand identity and discovery file.

Fetched from https://<domain>/.well-known/brand.json

The 5 branches of brand.json

Authoritative Location Redirect

Redirects to a hosted brand.json file at another URL

brand.json — Authoritative Location Redirect — 6 fields, 1 required
FieldTypeRequiredDescription
$schemastring
authoritative_locationstringrequiredHTTPS URL of the authoritative brand.json file
redirect_reasonstringOptional structured signal indicating why this redirect was put in place. One of: acquisition, divestiture, rebrand, regional, legacy, consolidation, other.
redirect_effective_atstringOptional timestamp when this redirect became effective.
notestringOptional human-readable rationale for the redirect.
last_updatedstring

House Redirect

Redirects to the house domain that contains the full brand portfolio

brand.json — House Redirect — 7 fields, 1 required
FieldTypeRequiredDescription
$schemastring
housedomainrequiredHouse domain to fetch brand portfolio from
regionstringISO 3166-1 alpha-2 country code if this is a regional domain
redirect_reasonstringOptional structured signal indicating why this redirect was put in place. One of: acquisition, divestiture, rebrand, regional, legacy, consolidation, other.
redirect_effective_atstringOptional timestamp when this redirect became effective.
notestringOptional human-readable rationale for the redirect.
last_updatedstring

Brand Agent

Brand represented by agents that provide brand info via MCP

brand.json — Brand Agent — 7 fields, 0 required
FieldTypeRequiredDescription
$schemastring
versionstring
agentsagents
brand_agentbrand_agent
contactcontact
data_subject_contestationdata_subject_contestation
last_updatedstring

House Portfolio

Full house/brand portfolio with hierarchy, creative assets, and properties.

brand.json — House Portfolio — 9 fields, 1 required
FieldTypeRequiredDescription
$schemastring
versionstring
househouserequired
brandsbrand[]Inline brands owned by this house (parent-owned data).
brand_refsportfolio_entry[]Portfolio entries for brands owned by this house that publish their own canonical brand.json elsewhere (child-owned data).
contactcontact
authorized_operatorsauthorized_operator[]Entities authorized to represent brands from this house.
trademarkstrademark[]House-level (corporate) registered trademarks.
last_updatedstring

Brand Canonical Document

Self-published brand document where the brand owns its own identity attributes.

brand.json — Brand Canonical Document — 4 fields, 0 required
FieldTypeRequiredDescription
$schemastring
versionstring
house_domaindomainOptional pointer to the corporate house this brand belongs to.
last_updatedstring
brand.json example 1 — source
{
  "$schema": "/schemas/3.1.13/brand.json",
  "authoritative_location": "https://adcontextprotocol.org/brand/abc123/brand.json"
}

Authenticity guarantees

Control of the domain is the only guarantee. The document carries no signature and the registry defines no schema for one. The only assertion a consumer can verify is that the file was served by the host it speaks for. AdCP does define an ownership challenge: a single-use nonce published either as a DNS TXT record at _adcp-owner.{domain} or as a file at /.well-known/adcp-ownership.txt, expiring fifteen minutes after issue. That challenge gates writes to AdCP's registry index. It does not gate the file on the publisher's own domain.

signing_keys pins the publisher-attested public keys an authorized agent is allowed to sign with. A verifier that finds a pin must reject any signature whose key is outside it, whatever the agent's own JWKS advertises. The field sits in core/authorized-agent-base.json next to url and authorized_for, and unlike those two it is not in required. The docs make it a MUST for any agent whose delegated scopes include mutating operations: create_media_buy, update_media_buy, sync_creatives and update_performance_index.

Two rules that reject a well-formed file

Both files are oneOf unions with overlapping branches: $schema and last_updated appear in all of them, and a document must satisfy exactly one branch. The first rule follows from that. A document carrying both authoritative_location and authorized_agents validates against both branches, which fails the oneOf under a draft-07 validator. The schema defines no pointer-with-inline-fallback shape.

The second is emptiness. authorized_agents may be empty, but only in a file that publishes something else. The inline branch wraps an anyOf over six arrays (authorized_agents, formats, properties, placements, collections, signals) and asks for one of them to be non-empty. The $comment on that anyOf says why: "a file with neither sales authorization nor non-empty catalog content is rejected." The authorized_agents description names the case it protects: a catalog-only community mirror, publishing a platform's formats and properties for a platform that has not adopted AdCP, where there is no sales agent to authorize. An empty array there asserts no sales authorization, and the schema tells validators not to read it as deny-all, authorize-all or a revocation.

Following authoritative_location

authoritative_location is an indirection: the well-known path holds a pointer and the real file lives at the URL it names. The rules for dereferencing it sit in the field description rather than in any schema keyword. Validators must refuse redirects on it and keep timeouts short. On a transient 5xx they serve the previously cached file. The size cap comes in two tiers, the smaller of them the general server-side request forgery (SSRF) cap: "pointer files served at /.well-known/adagents.json use the general 5 MB SSRF cap; dereferenced authoritative files (this URL's response, after the indirection) use a recommended 20 MB cap because the origin has explicitly opted in to fanning out across a publisher network." The 20 MB tier is sized for one file covering every property on a publisher network rather than one domain.

additionalProperties in adagents.json and brand.json

Both adagents.json branches set additionalProperties to true, and so do all six authorized_agents entry shapes. An agent entry whose key is misspelled — delegatoin_type in place of delegation_type — validates clean and has no effect. The correctly spelled key with an invalid value, delegation_type of "reseller", fails validation. The value is enum-constrained; the key name is not checked. Validation of a generated adagents.json therefore has to check key names against the six authorized_agents entry shapes rather than rely on a draft-07 pass.

brand.json, in the same release and the same registry, sets additionalProperties to false on four of its five branches: Authoritative Location Redirect, House Redirect, Brand Agent and House Portfolio. The identical misspelling in a House Portfolio file is therefore a hard error. The fifth branch, Brand Canonical Document, sets no additionalProperties and stays open. The release notes do not mention the difference.

Required fields inherited through allOf

Every authorized_agents entry requires url and authorized_for, and neither appears in the branch's own required list. Both are inherited through an allOf onto core/authorized-agent-base.json. A validator reports the two as missing against core/authorized-agent-base.json, not against the branch.

brand.json inherits required fields the same way. Its Brand Canonical Document branch is an allOf onto the shared brand definition, so id and names are required there even though the branch names neither. Its Brand Agent branch goes further: an empty required list plus an anyOf demanding agents or brand_agent.

authorization_type and the scope of a signal authorization

authorized_agents is a discriminated union on authorization_type. Four values scope inventory (property_ids, property_tags, inline_properties, publisher_properties), and signal_ids and signal_tags are the two that scope data. The four inventory branches carry delegation_type. On the brand.json side, relationship takes a fourth value, owned, which the schema describes as having no delegation_type counterpart.

The two data branches declare the discriminator and the selector only. countries, effective_from, effective_until and delegation_type are absent from both. Adding effective_until to a signal_tags entry still validates, because the object is open, and no consumer built from this schema reads the field. A time-bounded or geo-bounded signal authorization has no representation in the file.

A missing or malformed file

A 404 on the well-known path means the file is absent. Consumers proceed without verification; absence is not a denial, and the docs state that it does not mean the agent is unauthorized. A 404 or an S3-style 403 AccessDenied may send a validator to the domain's ads.txt for a managerdomain line instead, one hop only and only on those two statuses. Otherwise the publisher is unverifiable.

Unparseable JSON, or a missing top-level authorized_agents, aborts processing for that domain outright. A missing file does not. A single malformed property inside an otherwise-valid file must not either: validators skip that entry, log it and continue. A generation bug therefore causes a larger failure than hosting nothing, and the effect is largest on a managed-network file covering hundreds of publisher domains.

Frequently asked

What is adagents.json?
A file at /.well-known/adagents.json naming the agents a publisher or data provider allows to sell its inventory or resell its signals. Each entry needs a url, an authorized_for label, and an authorization_type saying what the authorization covers.
What is brand.json?
The buy-side half of the pair, hosted at /.well-known/brand.json. It declares who the brand is, which agents speak for it, and which properties it owns or sells. AdCP's docs line it up against sellers.json.
Can an adagents.json point at an authoritative copy and still list agents inline?
No. Both branches match, and a oneOf needs exactly one.

Related