Guides

sellers.json, ads.txt, and schain: the OpenRTB supply chain trust stack

Programmatic has a trust problem: a bid request can pass through several intermediaries before it reaches a buyer, and any of them could be misrepresenting whose inventory it is. Three artifacts exist to make that path auditable, and they only work together. ads.txt says who may sell, sellers.json says who each seller is, and the OpenRTB schain object records the actual path this request took. Here is how they interlock.

ads.txt: who is allowed to sell

ads.txt is a plain text file a publisher hosts at the root of its domain (example.com/ads.txt), listing the advertising systems authorized to sell its inventory and the publisher's account ID in each. The app equivalent is app-ads.txt. If a bid request claims to be selling example.com through an exchange that is not listed in example.com/ads.txt, a buyer has grounds to treat it as unauthorized. It is the publisher's public allowlist of sellers.

sellers.json: who each seller actually is

sellers.json is hosted by the advertising system, the SSP or exchange, at its own domain (ssp.com/sellers.json). It maps each seller account ID that can appear in that system to a real identity: a name, a domain, and whether the seller is a publisher selling its own inventory or an intermediary reselling someone else's. Where ads.txt is the publisher's list of its sellers, sellers.json is the seller's disclosure of its accounts. The two are designed to be cross-referenced.

schain: the path this request took

The first two files are static disclosures. The OpenRTB SupplyChain object, source.schain in 2.6, is dynamic: it travels inside each bid request and records the ordered list of every system that handled it, from the publisher out to the exchange sending it. Each node carries:

  • asi: the advertising system identifier, the domain of the system, which should match a sellers.json host.
  • sid: the seller ID within that system, which should match a seller entry in that system's sellers.json.
  • hp: whether this node is paid directly for the impression.

The chain also carries a complete flag: 1 asserts that every hop from the publisher is represented, 0 admits the chain is partial. A complete: 1 chain with a gap is worse than an honest 0.

How they cross-check

The three artifacts form a loop a buyer can verify without trusting any single party:

For each node in source.schain:
  node.asi  ->  is there a sellers.json at that domain?
  node.sid  ->  is that seller ID listed in that sellers.json?
  seller    ->  does the publisher's ads.txt authorize this system + account?

If every hop resolves, the path is accountable end to end.
A break at any step is a red flag, not necessarily fraud, but worth blocking.

This is also the foundation of supply path optimization (SPO): once the path is legible, a buyer can prefer the shortest, cleanest route to a given publisher and drop redundant or opaque intermediaries.

Where adagents.json fits

The agentic era adds a fourth file. adagents.json, served at /.well-known/adagents.json, is a publisher's declaration of which sales agents may represent its inventory, with scoped authorization beyond what ads.txt can express. It extends the same idea, verifiable authorization, into agent-brokered deals. See the AdCP explainer for the agent side.

Common failures worth checking

  • schain in the wrong path. In 2.6 it is source.schain, not the older source.ext.schain. Buyers reading the current path miss a chain in the old one.
  • asi that does not resolve. An asi with no sellers.json, or a sid not listed in it, defeats the whole verification.
  • Empty or duplicate nodes. A blank asi/sid or two identical adjacent nodes is a malformed chain.
  • Dishonest complete. Marking a partial chain complete is the failure that undermines trust the most.

Validate the chain

rtblint checks source.schain structure, node hygiene, duplicate adjacent nodes, missing hp, and empty identifiers as part of its semantic rule set. Paste a request into the tester to see it, or run the CLI over sampled traffic. The object-by-object breakdown is in the schain reference.

Sources