<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
 <!ENTITY nbsp "&#160;">
]>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-chowdhury-terms-txt-00" category="std" submissionType="IETF" version="3" tocInclude="true" sortRefs="true" symRefs="true">

<front>
  <title abbrev="terms.txt">terms.txt: Machine Access Terms and an Origin-Enforced Consent and Compensation Exchange</title>
  <seriesInfo name="Internet-Draft" value="draft-chowdhury-terms-txt-00"/>
  <author fullname="Rajarshi Chowdhury" initials="R." surname="Chowdhury">
    <organization>Independent</organization>
    <address><email>mailtorajarshi@gmail.com</email></address>
  </author>
  <date year="2026" month="September" day="10"/>
  <area>Web and Internet Transport</area>
  <keyword>terms.txt</keyword>
  <keyword>robots.txt</keyword>
  <keyword>Web Bot Auth</keyword>
  <keyword>AI crawlers</keyword>
  <keyword>agents</keyword>
  <keyword>HTTP 402</keyword>
  <abstract>
    <t>The Robots Exclusion Protocol lets an origin ask automated clients not to fetch certain paths. It cannot express who is asking, for what purpose, under what terms, or at what price, and it provides no server-side enforcement. This document specifies terms.txt, a file at a well-known location in the style of robots.txt that states, per path and per purpose, whether automated access is allowed, charged, or denied, at what use level, at what price, and whether a user's delegation is required. It also specifies the HTTP exchange that enforces the file at the origin: requests signed with Web Bot Auth, a signed declaration of intent, delegation tokens and payment vouchers bound to the authenticated identifier, payment negotiation signaled with Problem Details, and origin-signed receipts. The document states which properties the exchange enforces before delivery, which it can only audit afterward, and which remain contractual.</t>
  </abstract>
</front>

<middle>

<section anchor="intro"><name>Introduction</name>
  <t>The open web has operated on an implicit bargain: an origin admits crawlers, and search engines return visitors. Automated clients that fetch content to train models or to answer questions directly break that bargain, because the fetch still happens while the referral does not. Origins have responded with the only tool they widely hold, the Robots Exclusion Protocol <xref target="RFC9309"/>, which has proven inadequate in four ways. Its vocabulary of allow and disallow cannot distinguish fetching for indexing from fetching for training from fetching to answer a live request. It cannot state a price, a license, or a condition. It depends on the client identifying itself truthfully in a free-text User-Agent field. And it supplies no enforcement, so an origin that wishes to admit an archive but refuse a commercial training crawler has no way to say so and no way to check.</t>
  <t>Recent work addresses parts of this problem separately. Web Bot Auth <xref target="I-D.ietf-webbotauth-httpsig-protocol"/> lets an automated client sign its requests with HTTP Message Signatures <xref target="RFC9421"/> using keys published under an identifier it names, so an origin can verify that the holder of a published key signed the request. The AI Preferences work <xref target="I-D.ietf-aipref-vocab"/> <xref target="I-D.ietf-aipref-attach"/> defines a vocabulary for how content may be used and a way to attach those preferences to content, but by charter it expresses preferences and does not enforce them. Content delivery networks have shipped proprietary mechanisms that classify crawlers by purpose, return HTTP 402 to charged crawlers, and revoke the standing of operators that misbehave, but those mechanisms apply to an origin only because it routes traffic through a particular company.</t>
  <t>This document composes these pieces into one exchange that any origin can enforce. An origin publishes a terms.txt file (<xref target="file"/>) stating its terms per path and per purpose. A client fetches the file, then sends requests that are signed with Web Bot Auth, carry a signed declaration of purpose and use (<xref target="access-intent"/>), and, when the terms require it, carry a delegation token binding the request to a user's entitlements (<xref target="access-delegation"/>) or a payment voucher (<xref target="access-payment"/>). The origin verifies the signature, checks the declaration against its terms, and either serves the content with a signed receipt (<xref target="access-receipt"/>) or refuses with a status code and a Problem Details body <xref target="RFC9457"/> that states why, including the price and terms when payment is required.</t>

  <section anchor="scope"><name>Scope and Enforcement Boundary</name>
    <t>A signature over a declared purpose proves who made the declaration and that it was not altered in transit. It does not prove that the declaration is true. A signed receipt proves that content was delivered under stated terms. It does not prove what the recipient did with the content afterward. Once content leaves the origin, HTTP cannot govern its use.</t>
    <t>This document is therefore precise about three tiers. Properties in the first tier are enforced before delivery: the authenticated Web Bot Auth identifier of the requester, the freshness and uniqueness of the request, the binding of the signature to the full target URI, the presence and integrity of the declared intent, the validity and scope of a delegation, the match between the declaration and the terms, and the presence of a valid, unspent payment. Properties in the second tier are auditable after delivery: whether declared purpose matched observed behavior, which the receipt log and the signed declaration make attributable. Properties in the third tier are contractual: what a recipient does with lawfully delivered content, including whether it trains a model on it. This document makes the terms of the third tier explicit, attributable, and priced. It does not make them self-executing, and implementers MUST NOT describe it as doing so.</t>
  </section>
</section>

<section anchor="conventions"><name>Conventions and Definitions</name>
  <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP&nbsp;14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
  <t>This document applies to requests with the GET and HEAD methods. Requests with other methods are out of scope unless they also satisfy <xref target="signature"/>.</t>
  <t>This document uses the terms "origin", "user agent", "intermediary", "field", and "resource" as defined in <xref target="RFC9110"/>, and "Structured Field", "Dictionary", "String", and "Token" as defined in <xref target="RFC9651"/>. It uses "operator", "Signature Agent", and "key directory" as defined in <xref target="I-D.ietf-webbotauth-httpsig-protocol"/>.</t>
  <dl>
    <dt>Agent</dt><dd>An automated HTTP client. This document distinguishes four classes because terms differ by class: a training crawler, which fetches to build a model; a search crawler, which fetches to build an index that refers traffic; a service-operated agent, which fetches in real time on behalf of a service; and a user-delegated agent, which fetches on behalf of a specific person and can inherit that person's entitlements.</dd>
    <dt>Agent identifier</dt><dd>The identifier that results from successful Web Bot Auth resolution of the Signature-Agent member of a request, after the normalization that <xref target="I-D.ietf-webbotauth-httpsig-protocol"/> specifies. Under the default discovery type this is the resolved key directory URL. Tokens and receipts bind to this identifier, not to the raw field value. A valid signature establishes that a holder of a key published under this identifier signed the message; it does not by itself establish who operates the agent.</dd>
    <dt>Purpose</dt><dd>The reason for which an agent declares it is fetching a resource, drawn from the registry in <xref target="iana-purposes"/>.</dd>
    <dt>Use level</dt><dd>The extent to which the agent declares it will reproduce the fetched content: immediate, reference, or full (<xref target="use-levels"/>).</dd>
    <dt>Terms</dt><dd>The decision, use ceiling, price, and delegation requirement that an origin states for a given path and purpose in its terms.txt file.</dd>
    <dt>Receipt</dt><dd>A signed statement by the origin that a specific resource was delivered to a specific operator under specific terms.</dd>
    <dt>Settlement service</dt><dd>A party that issues payment vouchers an origin will accept. Its relationship to the origin and to the operator is out of scope.</dd>
    <dt>Identity provider</dt><dd>A party that issues delegation tokens on behalf of users. Its relationship to the origin and to the user is out of scope.</dd>
  </dl>
</section>

<section anchor="overview"><name>Overview of the Exchange</name>
  <t>Before its first request to an origin, an agent obtains its operator's signing key and, when needed, a delegation token from the user's identity provider and a payment voucher from a settlement service. It MAY fetch the origin's terms.txt file to learn what is required. The exchange then proceeds as follows.</t>
  <ol>
    <li>The agent sends an HTTP request carrying a Web Bot Auth signature (<xref target="signature"/>) and an Access-Intent field declaring purpose and use, together with Access-Delegation and Access-Payment fields when the terms require them. All of these fields are covered by the signature.</li>
    <li>The origin verifies the signature, including freshness, replay protection, and coverage of the full target URI, and retrieves the key from the key directory resolved from the Signature-Agent field, caching it under the pair of agent identifier and key identifier.</li>
    <li>The origin parses the Access-Intent field and locates the terms for the request path and declared purpose.</li>
    <li>If the terms require delegation, the origin validates the Access-Delegation token, including its binding to this agent identifier and its scope.</li>
    <li>If the terms charge for access, the origin validates the Access-Payment voucher and spends it atomically. If no valid, unspent voucher is present, it responds with status 403 and a Problem Details body of the "payment-required" type stating the price and terms (<xref target="status"/>).</li>
    <li>If every check passes, the origin serves the resource and returns an Access-Receipt field signed with a key it publishes at its own key directory, and appends the receipt to an append-only log.</li>
  </ol>
  <t>Unsigned requests, and signed requests that carry no Access-Intent field, are governed per path by the Unsigned directive of the applicable terms: served on paths marked allow, refused with a signature challenge on paths marked challenge, and refused on paths marked deny. No receipt is issued for them.</t>
</section>

<section anchor="file"><name>The terms.txt File</name>

  <section anchor="location"><name>Location and Retrieval</name>
    <t>An origin publishes its terms at the well-known URI <xref target="RFC8615"/> "/.well-known/terms.txt". The resource MUST be served with the media type text/plain and the UTF-8 charset. It SHOULD be cacheable, and origins are encouraged to set a Cache-Control max-age of at least one hour so that clients fetch it infrequently.</t>
    <t>Origins SHOULD include a Link field <xref target="RFC8288"/> with the relation type "access-terms" (<xref target="iana-link"/>) on responses to automated clients, pointing at the terms resource, so that a client that did not fetch the file in advance learns where it is.</t>
    <t>The file applies to the origin at which it is served, in the sense of <xref target="RFC6454"/>. It does not apply to other origins, including other ports or schemes at the same host.</t>
  </section>

  <section anchor="syntax"><name>Syntax</name>
    <t>The file is a sequence of lines. Each non-empty, non-comment line is a field name, a colon, and a value, optionally followed by a comment. Field names are case-insensitive. Header fields precede one or more Path blocks. A Path block begins with a Path line and continues until the next Path line or the end of the file. The grammar in ABNF <xref target="RFC5234"/> is as follows; the final line of a file MAY omit its line terminator.</t>
    <sourcecode type="abnf"><![CDATA[
terms-file    = *( header-line / skip ) 1*path-block

header-line   = ( version-hdr / terms-id-hdr / receipt-keys-hdr
                / payment-hdr / purposes-hdr / uses-hdr ) end
version-hdr   = "Version:" WS 1*DIGIT
terms-id-hdr  = "Terms-Id:" WS id
receipt-keys-hdr = "Receipt-Keys:" WS uri
payment-hdr   = "Payment:" WS method [ WS uri ]
purposes-hdr  = "Purposes:" WS purpose *( WS purpose )
uses-hdr      = "Uses:" WS use-level *( WS use-level )

path-block    = path-line *( unsigned-line / purpose-line / skip )
path-line     = "Path:" WS path-prefix end
unsigned-line = "Unsigned:" WS ( "allow" / "challenge" / "deny" ) end
purpose-line  = "Purpose:" WS purpose WS decision *( WS option ) end

decision      = "allow" / "charge" / "deny"
option        = price / use-option / delegation-option
price         = amount WS currency "/" unit
amount        = 1*DIGIT [ "." 1*DIGIT ]
currency      = 3ALPHA
unit          = id
use-option    = "use=" use-level
delegation-option = "delegation=" scope
use-level     = "immediate" / "reference" / "full"

purpose       = id
scope         = id
method        = id
id            = 1*( ALPHA / DIGIT / "-" / "_" / "." / ":" )
path-prefix   = "/" *( VCHAR-nohash )
uri           = <absolute-URI or path-absolute, RFC 3986>

end           = [ WS ] [ comment ] EOL
skip          = [ WS ] [ comment ] EOL
comment       = "#" *VCHAR
VCHAR-nohash  = %x21-22 / %x24-7E
WS            = 1*WSP
EOL           = [ CR ] LF
]]></sourcecode>
    <t>A "#" and everything after it on a line is a comment and is ignored; a path-prefix therefore cannot contain "#". Lines that do not match the grammar MUST cause the entire file to be rejected; an origin whose file fails to parse has stated no terms, and clients MUST treat it as if no terms.txt were present. A header field other than Payment that appears more than once is a parse error.</t>
  </section>

  <section anchor="header-fields"><name>Header Fields</name>
    <dl>
      <dt>Version</dt><dd>The version of this specification the file conforms to. This document defines version 1. Files without a Version line are version 1. A client that encounters a Version it does not implement MUST treat the file as absent.</dd>
      <dt>Terms-Id</dt><dd>An opaque identifier for this edition of the terms, chosen by the origin. It is echoed in receipts and payment-required responses so that a receipt can be matched to the terms in force when it was issued. Origins MUST change the identifier whenever the file changes.</dd>
      <dt>Receipt-Keys</dt><dd>The URI of a key directory, in the format defined by <xref target="I-D.ietf-webbotauth-httpsig-protocol"/>, at which the origin publishes the public keys it signs receipts with. A relative reference is resolved against the origin. Origins that issue receipts MUST include this field.</dd>
      <dt>Payment</dt><dd>A payment method the origin accepts, followed by the URI of the settlement service for that method. This document defines the method "voucher" (<xref target="access-payment"/>). The field MAY appear more than once, once per method; each occurrence pairs one method with one settlement URI. Origins that use the charge decision MUST include at least one Payment field.</dd>
      <dt>Purposes</dt><dd>The purpose names the origin recognizes. If absent, the origin recognizes the initial registry contents (<xref target="iana-purposes"/>). A Purpose line naming a purpose not in this set is a parse error.</dd>
      <dt>Uses</dt><dd>The ordered list of use levels the origin recognizes, from least to most extensive. If absent, the list is "immediate reference full".</dd>
    </dl>
  </section>

  <section anchor="path-blocks"><name>Path Blocks</name>
    <t>A request matches the Path block whose path-prefix is the longest prefix of the request's path component. Before comparison, both the request path and each path-prefix are normalized as in <xref target="RFC9309"/>: percent-encoded octets that correspond to unreserved characters <xref target="RFC3986"/> are decoded, hexadecimal digits in remaining percent-encodings are uppercased, and percent-encoded reserved characters such as "%2F" are left encoded, since decoding them would change the path's structure. Comparison is then byte-wise. A request that matches no block has no terms and MUST be treated by the origin according to its local policy; this document RECOMMENDS treating it as if the block "Path: /" with "Unsigned: allow" and no Purpose lines applied, which serves unsigned traffic and refuses every declared purpose.</t>
    <t>Within a block:</t>
    <dl>
      <dt>Unsigned</dt><dd>The policy for requests that carry no signature. "allow" serves the resource without a receipt. "challenge" refuses with status 403 and an Accept-Signature field (<xref target="challenge"/>). "deny" refuses with status 403. The default is "allow".</dd>
      <dt>Purpose</dt><dd>The terms for one declared purpose. The decision is one of "allow", "charge", or "deny". A "use=" option sets the maximum use level a client may declare; a declaration above the ceiling is refused. A "delegation=" option requires a valid delegation token whose scope claim includes the named scope. A price is REQUIRED when the decision is "charge" and MUST NOT appear otherwise; its unit names what is being priced, and this document defines the unit "request".</dd>
    </dl>
    <t>A purpose that has no Purpose line in the matching block is refused. Origins that wish to admit a purpose must say so.</t>
  </section>

  <section anchor="purposes"><name>Purpose Names</name>
    <t>Purpose names are registered in the registry established in <xref target="iana-purposes"/>. The initial registry contains:</t>
    <dl>
      <dt>search</dt><dd>Fetching to build an index from which the origin will receive referrals. Analogous to the "search" category of <xref target="I-D.ietf-aipref-vocab"/>, with one difference: in that vocabulary "search" excludes producing summaries, whereas here the use level, not the purpose, governs how much of the content may be reproduced.</dd>
      <dt>agent</dt><dd>Fetching in real time to satisfy a request from a service or a person, for example to ground an answer.</dd>
      <dt>train-ai</dt><dd>Fetching to train or fine-tune a model. Analogous to the "train-ai" category of <xref target="I-D.ietf-aipref-vocab"/>.</dd>
      <dt>archive</dt><dd>Fetching to preserve the resource in a public archive.</dd>
      <dt>research</dt><dd>Fetching for non-commercial research.</dd>
    </dl>
    <t>The last two are included because measurements of robots.txt deployment show that origins reacting to commercial training crawlers block archives and research crawlers as collateral damage, since the Robots Exclusion Protocol cannot distinguish them. Giving them names lets an origin admit them explicitly.</t>
    <t>The registry is independent of the AI Preferences vocabulary, whose own text notes that it does not yet have working group consensus. Where a name here has an analogue there, the registry entry says so; the names are not claimed to be identical.</t>
  </section>

  <section anchor="use-levels"><name>Use Levels</name>
    <t>A use level describes how much of the fetched content the agent declares it will reproduce to its own users. "immediate" means a short excerpt or a fact extracted from the content. "reference" means a summary or a paraphrase with attribution. "full" means reproduction of the content in whole or substantial part. The levels are ordered, and a terms ceiling of a given level admits declarations at that level and below. The three levels are those of a proposed extension to the Content Signals convention <xref target="CONTENT-SIGNALS"/> described in <xref target="CLOUDFLARE-AI-OPTIONS"/>; the convention itself defines the categories ai-train, search, and ai-input and does not define use levels. Adopting the extension's names lets an origin that already publishes that signal in robots.txt state enforceable terms in the same words.</t>
  </section>

  <section anchor="example-file"><name>Example</name>
    <artwork type="text"><![CDATA[
# /.well-known/terms.txt
Version: 1
Terms-Id: 2026-09-01
Receipt-Keys: /.well-known/http-message-signatures-directory
Payment: voucher https://settle.example/.well-known/settlement

Path: /articles/
Unsigned: allow
Purpose: search    allow   use=reference
Purpose: agent     allow   use=reference  delegation=articles
Purpose: train-ai  charge  0.002 USD/request
Purpose: archive   allow   use=full
Purpose: research  allow   use=full

Path: /premium/
Unsigned: challenge
Purpose: search    allow   use=reference
Purpose: agent charge 0.01 USD/request use=reference delegation=premium
Purpose: train-ai  deny
Purpose: archive   allow   use=full
Purpose: research  allow   use=full
]]></artwork>
    <t>Under these terms, an unsigned browser is served from /articles/ and challenged on /premium/. A search crawler is admitted everywhere at the reference level. A training crawler pays per request under /articles/ and is refused under /premium/. A user-delegated agent is admitted under /articles/ if its delegation carries the articles scope, and under /premium/ only with the premium scope and a payment voucher.</t>
  </section>
</section>

<section anchor="request-fields"><name>Request Fields</name>

  <section anchor="access-intent"><name>Access-Intent</name>
    <t>The Access-Intent request field declares the purpose and use level of the request. It is a Structured Field Dictionary <xref target="RFC9651"/> with the following members:</t>
    <dl>
      <dt>purpose</dt><dd>A String or Token naming a registered purpose. REQUIRED.</dd>
      <dt>use</dt><dd>A String or Token naming a use level. OPTIONAL; the default is "reference".</dd>
    </dl>
    <artwork type="text"><![CDATA[
Access-Intent: purpose="agent", use="reference"
]]></artwork>
    <t>The field MUST be a covered component of the request signature (<xref target="signature"/>). An origin MUST refuse with status 400 a request whose Access-Intent field is present but not covered, since an intermediary could otherwise add or alter the declaration. A signed request that carries no Access-Intent field is processed under the Unsigned directive of the matching Path block, so that clients implementing Web Bot Auth without this document are neither privileged nor broken.</t>
  </section>

  <section anchor="access-delegation"><name>Access-Delegation</name>
    <t>The Access-Delegation request field carries a delegation token (<xref target="tokens"/>) asserting that the request is made on behalf of a user who holds an entitlement at the origin. The token is issued by an identity provider the origin trusts; how the origin comes to trust an identity provider is out of scope. The field MUST be a covered component of the request signature.</t>
    <t>A delegation token's claims are:</t>
    <dl>
      <dt>iss</dt><dd>The identity provider, as an origin.</dd>
      <dt>sub</dt><dd>A pairwise pseudonym for the user, stable for this identity provider and this origin but not correlatable across origins.</dd>
      <dt>aud</dt><dd>The origin the token is valid for.</dd>
      <dt>agent</dt><dd>The agent identifier (<xref target="conventions"/>) permitted to present the token. A token presented in a request that resolves to a different agent identifier MUST be refused.</dd>
      <dt>scope</dt><dd>An array of scope identifiers the user has delegated.</dd>
      <dt>iat, exp</dt><dd>Issuance and expiry times in seconds since the Unix epoch.</dd>
    </dl>
  </section>

  <section anchor="access-payment"><name>Access-Payment</name>
    <t>The Access-Payment request field carries a payment credential for a charged request. Its value is a method name, a space, and a method-specific credential. This document defines the "voucher" method, whose credential is a token (<xref target="tokens"/>) issued by a settlement service the origin accepts. The field MUST be a covered component of the request signature.</t>
    <t>A voucher's claims are:</t>
    <dl>
      <dt>iss</dt><dd>The settlement service, as an origin.</dd>
      <dt>aud</dt><dd>The origin the voucher is valid for.</dd>
      <dt>agent</dt><dd>The agent identifier permitted to spend it.</dd>
      <dt>path</dt><dd>A path prefix the voucher may be spent under.</dd>
      <dt>amount, currency, unit</dt><dd>The value of the voucher and the unit it prices, matching the unit of the terms it is meant to satisfy. Amounts are exact decimal strings, for example "0.01", never JSON numbers. A voucher MUST NOT be accepted for a resource whose price exceeds its amount, whose currency differs, or whose unit differs.</dd>
      <dt>id</dt><dd>A unique identifier. An origin MUST accept a given identifier at most once, and MUST check and record the identifier as spent in one atomic operation so that two requests presenting the same voucher concurrently cannot both succeed.</dd>
      <dt>exp</dt><dd>Expiry time in seconds since the Unix epoch.</dd>
    </dl>
    <t>How the settlement service is funded, how it settles with the origin, and whether the unit of account is the request, the citation, the answer, or the transaction are out of scope. The receipt defined in <xref target="access-receipt"/> is designed to make any of those units measurable.</t>
  </section>

  <section anchor="signature"><name>Signature Requirements</name>
    <t>Requests that carry an Access-Intent field MUST be signed as specified in <xref target="I-D.ietf-webbotauth-httpsig-protocol"/>. This document profiles that specification as follows:</t>
    <ul>
      <li>The covered components MUST include "@method", "@target-uri", the "signature-agent" field member keyed by the signature label, and "access-intent". They MUST also include "access-delegation" and "access-payment" whenever those fields are present. Covering "@target-uri" rather than "@path" binds the scheme, authority, path, and query; a signature that covered only the path would let an intermediary or attacker alter the query without invalidating it.</li>
      <li>Requests with a method other than GET or HEAD MUST also carry a Content-Digest field <xref target="RFC9530"/> and cover it.</li>
      <li>The signature parameters MUST include "created", "expires", "nonce", "keyid", and tag="web-bot-auth". The interval between "created" and "expires" MUST NOT exceed 300 seconds.</li>
      <li>Signing keys MUST be Ed25519 keys. The "alg" parameter MAY be omitted; if present, its value MUST be "ed25519", the identifier registered for HTTP Message Signatures, which is distinct from the JOSE identifier used in <xref target="tokens"/>.</li>
      <li>"keyid" MUST be the JWK Thumbprint <xref target="RFC7638"/> of the signing key, computed as specified for OKP keys in <xref target="RFC8037"/>.</li>
    </ul>
    <t>An origin MUST look keys up by the pair of agent identifier and key identifier, and MUST NOT accept a key found under one identifier's directory for a request that resolves to another.</t>
  </section>
</section>

<section anchor="response-fields"><name>Response Fields and Status Codes</name>

  <section anchor="access-receipt"><name>Access-Receipt</name>
    <t>On every response that serves a resource to a signed request, the origin MUST include an Access-Receipt field whose value is a token (<xref target="tokens"/>) signed with a key published at the origin's Receipt-Keys directory. Its claims are:</t>
    <dl>
      <dt>iss</dt><dd>The origin.</dd>
      <dt>kid</dt><dd>The thumbprint of the signing key.</dd>
      <dt>agent</dt><dd>The agent identifier served.</dd>
      <dt>sub</dt><dd>The subject pseudonym from the delegation token, or null.</dd>
      <dt>purpose, use</dt><dd>The declared purpose and use level.</dd>
      <dt>terms_id, terms_digest</dt><dd>The Terms-Id in force and the base64url-encoded SHA-256 digest of the terms.txt representation it names, so that the receipt proves what the terms contained and not only what they were called.</dd>
      <dt>method, target</dt><dd>The request method and the full target URI.</dd>
      <dt>status</dt><dd>The response status code.</dd>
      <dt>content_digest</dt><dd>The value of the response's Content-Digest field <xref target="RFC9530"/>, binding the receipt to the representation delivered. Origins that issue receipts MUST include a Content-Digest field on receipted responses.</dd>
      <dt>req</dt><dd>The base64url-encoded SHA-256 hash of the request's Signature field value, binding the receipt to one signed request.</dd>
      <dt>ts</dt><dd>Issuance time in seconds since the Unix epoch.</dd>
      <dt>id</dt><dd>A unique identifier.</dd>
    </dl>
    <t>The origin SHOULD append each receipt to an append-only log whose entries are hash-chained, so that the log head commits to every receipt issued. The receipt gives both parties a non-repudiable record of which representation was delivered to which agent identifier under which terms, which is the input any settlement model or dispute requires. A receipt is evidence for the one request whose Signature field it hashes and for no other; in particular, a receipt obtained from a cache is not a receipt for the request that hit the cache (<xref target="caching"/>).</t>
  </section>

  <section anchor="link"><name>The "access-terms" Link Relation</name>
    <t>A Link field with relation type "access-terms" identifies the origin's terms.txt resource. Origins SHOULD include it on 400 and 403 responses to automated clients and MAY include it on 200 responses.</t>
  </section>

  <section anchor="status"><name>Status Codes</name>
    <t>This document uses existing HTTP status codes with their defined semantics <xref target="RFC9110"/> and conveys the specific reason in a Problem Details body <xref target="RFC9457"/>, in accordance with BCP&nbsp;56 <xref target="RFC9205"/>. It does not use 401, which requires a WWW-Authenticate field that no HTTP authentication scheme here would supply, and it does not use 402, which RFC 9110 reserves and whose semantics this document is not the place to define.</t>
    <dl>
      <dt>200</dt><dd>The request satisfied the terms. The response carries an Access-Receipt field.</dd>
      <dt>400</dt><dd>The request's signature fields or Access-Intent field are malformed, required signature parameters are absent, or a field that this document requires to be covered is present but not covered.</dd>
      <dt>403</dt><dd>The request is refused. The Problem Details "type" states why: the request is unsigned on a path marked challenge or deny; the signature could not be verified (unknown key, signature over a different message, expired or stale); the nonce was already used; the purpose is denied or unknown, or the declared use exceeds the ceiling; a required delegation is absent, invalid, expired, out of scope, or bound to another agent identifier; or the terms charge for this purpose and no valid, unspent payment was presented. An origin MAY answer repeated replays from one agent identifier with 429 instead.</dd>
    </dl>
    <t>Every 403 response under this document MUST carry a Problem Details body of media type application/problem+json and Cache-Control: no-store. For payment, the "type" member is the "payment-required" problem type registered in <xref target="iana-problem"/>, and the body carries these additional members: "terms_id"; "purpose"; "price", an object with "amount" (an exact decimal string), "currency", and "unit"; "payment", an array of objects each with "method" and "settlement", so that each method is paired with its settlement URI; and "terms", the URI of the terms resource. For other refusals the "type" member is the "terms-refused" problem type and the body SHOULD carry "reason", one of "unsigned", "signature-invalid", "replay", "purpose-refused", "use-exceeds-terms", or "delegation-required".</t>
    <t>Deployed systems that charge crawlers have used status 402 for the payment case. This document does not depend on that usage. Should the HTTP Working Group define semantics for 402, a future version of this document can adopt them.</t>
  </section>

  <section anchor="challenge"><name>Signature Challenge</name>
    <t>When an unsigned request arrives on a path whose Unsigned directive is "challenge", the origin responds with status 403, a Problem Details body with reason "unsigned", and an Accept-Signature field as defined in <xref target="RFC9421"/> listing the components and parameters the origin requires, which is the behavior <xref target="I-D.ietf-webbotauth-httpsig-protocol"/> recommends for requesting a signature. For example:</t>
    <artwork type="text"><![CDATA[
Accept-Signature: sig1=("@method" "@target-uri"
  "signature-agent";key="sig1" "access-intent");created;expires;
  nonce;keyid;tag="web-bot-auth"
]]></artwork>
  </section>
</section>

<section anchor="tokens"><name>Token Format</name>
  <t>Delegation tokens, payment vouchers, and receipts are JSON Web Signatures in Compact Serialization <xref target="RFC7515"/> signed with Ed25519 <xref target="RFC8032"/>. The JOSE header MUST contain "alg" with the value "Ed25519", the fully specified identifier registered by <xref target="RFC9864"/>, and "kid" with the thumbprint of the signing key. The deprecated polymorphic identifier "EdDSA" <xref target="RFC8037"/> MUST NOT be used. The payload is the JSON object of claims <xref target="RFC8259"/>. Verifiers MUST reject a token whose "alg" is anything else, whose signature does not verify under the key identified by "kid" at the expected issuer, or whose "exp" claim is in the past.</t>
  <t>Verifiers MUST enforce audience and agent binding. A token whose "aud" is not this origin, or whose "agent" is not the agent identifier that the request's Signature-Agent resolved to, MUST be refused. These two checks are what make a stolen token useless at any other origin or under any other identifier.</t>
</section>

<section anchor="origin-keys"><name>Origin Key Publication</name>
  <t>An origin that issues receipts publishes the corresponding public keys at the directory named by Receipt-Keys, using the same directory format and the same thumbprint key identifiers as <xref target="I-D.ietf-webbotauth-httpsig-protocol"/>. A third party verifying a receipt fetches the directory, selects the key whose thumbprint matches the receipt's "kid", and verifies the signature. Reusing the Web Bot Auth directory format means origins and operators publish keys the same way.</t>
</section>

<section anchor="processing"><name>Processing Rules</name>

  <section anchor="origin-processing"><name>Origin</name>
    <t>On receiving a request for a resource governed by terms.txt, an origin proceeds in the following order. The order matters for security: inexpensive checks precede cryptography, and replay reservation precedes any asynchronous discovery.</t>
    <ol>
      <li>Locate the Path block for the request. If the request is unsigned, or signed but without an Access-Intent field, apply the Unsigned directive and stop.</li>
      <li>Parse the Signature-Input field. Refuse with 400 if the tag, "created", "expires", "nonce", or "keyid" parameters are absent or malformed, if an "alg" parameter is present with a value other than "ed25519", or if the components required by <xref target="signature"/> are not covered. Refuse with 403 if the signature is expired or stale.</li>
      <li>Resolve the Signature-Agent member to an agent identifier as <xref target="I-D.ietf-webbotauth-httpsig-protocol"/> specifies. Atomically check and reserve the tuple of agent identifier, "keyid", and "nonce" in a replay store scoped to at least the signature validity window. If the tuple is already present, refuse with 403 (or 429). The reservation MUST happen before any network operation, so that two identical requests racing a cold key lookup cannot both succeed. If a later step fails, the reservation MAY be released.</li>
      <li>Obtain the key, from cache or by fetching the directory. Fetches MUST be bounded in size and time, MUST NOT follow redirects, and SHOULD be coalesced so that concurrent requests naming one directory cause one fetch. Verify the signature; refuse with 403 on failure.</li>
      <li>Parse Access-Intent. Refuse with 400 if it is not covered by the signature. Locate the Purpose line; refuse with 403 if there is none, if the decision is deny, or if the declared use exceeds the ceiling.</li>
      <li>If the terms require delegation, validate the Access-Delegation token as specified in <xref target="tokens"/> and <xref target="access-delegation"/>, including scope; refuse with 403 on failure.</li>
      <li>If the decision is charge, validate the Access-Payment voucher and atomically check and record its identifier as spent; respond with 403 and the "payment-required" problem type if it is absent, invalid, insufficient, of the wrong unit, expired, or already spent.</li>
      <li>Serve the resource with Content-Digest and Access-Receipt fields and append the receipt to the log.</li>
    </ol>
  </section>

  <section anchor="client-processing"><name>Client</name>
    <t>A client SHOULD fetch and cache the origin's terms.txt before its first governed request, and MUST refetch it when a 403 response carries a Link with the "access-terms" relation and the client's cached copy is older than the response. A client MUST declare a purpose it can substantiate and a use level it will not exceed. A client MUST NOT retry a refused request with a different declared purpose for the same fetch in order to find one the terms admit; it MAY select a purpose from the terms before the request.</t>
    <t>A client SHOULD verify the Access-Receipt it receives against the origin's published key and retain it, since the receipt is its evidence of the terms it was served under.</t>
  </section>
</section>

<section anchor="caching"><name>Caching and Intermediaries</name>
  <t>A receipt is evidence for exactly one signed request. A response stored by any cache <xref target="RFC9111"/>, shared or private, and reused for a later request would carry a receipt that hashes a different request's signature, and the origin would have issued no receipt and logged nothing for the later one. Origins MUST therefore mark responses that carry an Access-Receipt with Cache-Control: no-store. Responses to unsigned requests are unaffected and remain cacheable as today. A future version of this document may define a cacheable variant in which the receipt is obtained separately from the representation.</t>
  <t>Because the signature covers the full target URI and the request fields defined here, an intermediary in front of the origin may forward the request unchanged for the origin to verify, or may verify on the origin's behalf and convey the result by a mechanism outside this document. An intermediary that rewrites a covered component invalidates the signature, which is the intended failure.</t>
</section>

<section anchor="security"><name>Security Considerations</name>
  <t>The security considerations of <xref target="RFC9421"/> and <xref target="I-D.ietf-webbotauth-httpsig-protocol"/> apply. The following are specific to this document.</t>
  <t><strong>False declarations.</strong> Nothing in this document prevents an operator from declaring a purpose or use level that does not match its behavior. What the signed declaration provides is attribution: an operator that declares reference use and reproduces content in full, or declares search and never refers, leaves evidence in receipts, in its own outputs, and in traffic, and that evidence names the operator. The remedy is revocation of the operator's standing, which is outside this document.</t>
  <t><strong>Target binding.</strong> A signature that covered only the path would leave the query string unbound, so that a request for one resource could be replayed against another at the same path. Covering "@target-uri" closes this. Requests with bodies are out of scope unless the body is covered through Content-Digest, since an uncovered body is likewise alterable.</t>
  <t><strong>Credential theft.</strong> Signature validity is bounded to 300 seconds. Delegation tokens and vouchers are bound to an audience and an agent identifier, so a token stolen from one agent cannot be presented under another identifier. Key rotation is handled through the key directory.</t>
  <t><strong>Replay.</strong> The replay store is the only defense against reuse of a captured signed request within its validity window. It MUST be consulted and updated atomically, before any asynchronous operation, and in multi-instance deployments MUST be shared across instances. A first version of the reference implementation reserved the nonce after key discovery and was vulnerable to two identical requests racing a cold lookup.</t>
  <t><strong>Cost-based denial of service.</strong> Verification costs the origin CPU per request and an attacker can force it. Origins SHOULD order cheap checks before cryptography, as in <xref target="origin-processing"/>, SHOULD rate-limit per Signature Agent URL, and can rely on the observation that refusing a request costs less than serving one. In the reference implementation on a single shared vCPU, rejecting a forged signature cost 0.21 ms and a payment refusal 0.37 ms, against 0.65 ms for a paid, receipted response.</t>
  <t><strong>Identity.</strong> A verified signature establishes that a holder of a key published under the resolved agent identifier signed the request. It does not establish who operates the agent, and an origin that needs a real-world identity behind an identifier must obtain it by other means, for example the operator registry that <xref target="I-D.ietf-webbotauth-httpsig-protocol"/> anticipates. This document's terms, tokens, and receipts bind to the identifier, and its guarantees are stated in those terms.</t>
  <t><strong>Directory fetching.</strong> Fetching an operator's key directory is a server-side request to a URL named by the client. Origins MUST apply the discovery protections of <xref target="I-D.ietf-webbotauth-httpsig-protocol"/>, including bounding response size and time, refusing redirects, and refusing non-HTTPS or non-origin URLs.</t>
  <t><strong>Unauthenticated clients.</strong> This document does not defeat scraping by clients that do not sign. It makes signed access more capable than unsigned access, since only signed requests can obtain delegated entitlements, paid content, or receipts, and it lets an origin require signatures on the paths where it matters.</t>
</section>

<section anchor="privacy"><name>Privacy Considerations</name>
  <t>The exchange reveals the operator's identity to the origin on every request; that is its purpose. It is designed not to reveal the user's identity. The delegation token's subject is a pairwise pseudonym chosen by the identity provider, stable for one identity provider and one origin, so that an origin can recognize a returning subscriber's agent without learning who the subscriber is or correlating them across origins. Receipts carry the pseudonym and no other user identifier. Identity providers MUST NOT use a globally stable identifier as the subject.</t>
  <t>The terms.txt file itself is public and reveals an origin's pricing and policy. Origins that consider that sensitive can state terms only for the purposes they wish to admit.</t>
</section>

<section anchor="iana"><name>IANA Considerations</name>

  <section anchor="iana-wk"><name>Well-Known URI Registration</name>
    <t>IANA is requested to register the following in the "Well-Known URIs" registry <xref target="RFC8615"/>:</t>
    <dl>
      <dt>URI suffix</dt><dd>terms.txt</dd>
      <dt>Change controller</dt><dd>IETF</dd>
      <dt>Specification document</dt><dd>This document, <xref target="location"/>.</dd>
      <dt>Status</dt><dd>permanent</dd>
    </dl>
    <t>On the name: <xref target="RFC8615"/> discourages names that are overly generic. "terms.txt" is proposed because the resource is a text file of access terms and because the name signals, to the site operators who must deploy it, continuity with robots.txt, which is the mechanism it extends. Should the designated expert prefer a more specific name, "access-terms.txt" preserves both properties.</t>
  </section>

  <section anchor="iana-fields"><name>HTTP Field Name Registrations</name>
    <t>IANA is requested to register the following in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" <xref target="RFC9110"/>, each with status "permanent" and this document as reference: Access-Intent (<xref target="access-intent"/>), Access-Delegation (<xref target="access-delegation"/>), Access-Payment (<xref target="access-payment"/>), and Access-Receipt (<xref target="access-receipt"/>).</t>
  </section>

  <section anchor="iana-link"><name>Link Relation Registration</name>
    <t>IANA is requested to register the following in the "Link Relation Types" registry <xref target="RFC8288"/>:</t>
    <dl>
      <dt>Relation name</dt><dd>access-terms</dd>
      <dt>Description</dt><dd>Refers to a resource stating the terms under which automated clients may access the context resource.</dd>
      <dt>Reference</dt><dd>This document, <xref target="link"/>.</dd>
    </dl>
  </section>

  <section anchor="iana-problem"><name>HTTP Problem Type Registrations</name>
    <t>IANA is requested to register the following in the "HTTP Problem Types" registry <xref target="RFC9457"/>:</t>
    <dl>
      <dt>Type URI</dt><dd>https://iana.org/assignments/http-problem-types#payment-required</dd>
      <dt>Title</dt><dd>Payment required by access terms</dd>
      <dt>Recommended HTTP status code</dt><dd>403</dd>
      <dt>Reference</dt><dd>This document, <xref target="status"/>.</dd>
    </dl>
    <dl>
      <dt>Type URI</dt><dd>https://iana.org/assignments/http-problem-types#terms-refused</dd>
      <dt>Title</dt><dd>Refused by access terms</dd>
      <dt>Recommended HTTP status code</dt><dd>403</dd>
      <dt>Reference</dt><dd>This document, <xref target="status"/>.</dd>
    </dl>
  </section>

  <section anchor="iana-purposes"><name>terms.txt Purpose Names Registry</name>
    <t>IANA is requested to establish a "terms.txt Purpose Names" registry with the "Specification Required" policy <xref target="RFC8126"/>. Each entry has a name, a description, and a reference. The initial contents are the five names defined in <xref target="purposes"/>, with this document as reference. Designated experts SHOULD keep names aligned with the categories of <xref target="I-D.ietf-aipref-vocab"/> where the meanings coincide.</t>
  </section>
</section>

<section anchor="impl-status"><name>Implementation Status</name>
  <t>This section records the status of known implementations as described in <xref target="RFC7942"/>. It will be removed before publication as an RFC.</t>
  <t>A reference implementation in dependency-free JavaScript on Node.js 22 is archived at <xref target="TERMS-TXT-IMPL"/> and developed at https://github.com/rch0wdhury/terms-txt under the MIT license. It implements the terms.txt parser, the origin processing rules of <xref target="origin-processing"/>, a directory resolver, and a harness of 24 conformance and correctness checks, including verification of the Ed25519 test vector E.2.1 of <xref target="I-D.ietf-webbotauth-httpsig-protocol"/>, sequential and concurrent replay rejection, pair-scoped key lookup, scope and agent binding of delegation tokens, single-use vouchers, per-path unsigned policy, and hash-chain verification of the receipt log. Measured on one shared vCPU over loopback, identity verification added 0.20 ms per request over a passthrough server, a receipted search request 0.34 ms, a delegated request 0.49 ms, a payment refusal 0.37 ms, and a paid receipted request 0.65 ms.</t>
  <t>Release v0.1 predates this document and deviates from it in the following respects, all of which are scheduled for the next release: it covers "@path" rather than "@target-uri"; it answers unverifiable signatures with 401 and payment with 402 rather than 403 with Problem Details; its tokens use a two-part payload-and-signature form rather than JWS with "alg" "Ed25519"; it binds tokens and receipts to the raw Signature-Agent value rather than the resolved agent identifier; its receipts omit the response status, Content-Digest, and terms digest; its vouchers omit the unit and encode amounts as numbers; it marks receipted responses private rather than no-store; and its Link relation is named "terms". Its measurements are reported for that release.</t>
</section>

</middle>

<back>
  <references><name>References</name>
    <references><name>Normative References</name>
      <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119"><front><title>Key words for use in RFCs to Indicate Requirement Levels</title><author initials="S." surname="Bradner"/><date year="1997" month="March"/></front><seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="2119"/><seriesInfo name="DOI" value="10.17487/RFC2119"/></reference>
      <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174"><front><title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title><author initials="B." surname="Leiba"/><date year="2017" month="May"/></front><seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="8174"/><seriesInfo name="DOI" value="10.17487/RFC8174"/></reference>
      <reference anchor="RFC3986" target="https://www.rfc-editor.org/info/rfc3986"><front><title>Uniform Resource Identifier (URI): Generic Syntax</title><author initials="T." surname="Berners-Lee"/><author initials="R." surname="Fielding"/><author initials="L." surname="Masinter"/><date year="2005" month="January"/></front><seriesInfo name="STD" value="66"/><seriesInfo name="RFC" value="3986"/><seriesInfo name="DOI" value="10.17487/RFC3986"/></reference>
      <reference anchor="RFC5234" target="https://www.rfc-editor.org/info/rfc5234"><front><title>Augmented BNF for Syntax Specifications: ABNF</title><author initials="D." surname="Crocker"/><author initials="P." surname="Overell"/><date year="2008" month="January"/></front><seriesInfo name="STD" value="68"/><seriesInfo name="RFC" value="5234"/><seriesInfo name="DOI" value="10.17487/RFC5234"/></reference>
      <reference anchor="RFC6454" target="https://www.rfc-editor.org/info/rfc6454"><front><title>The Web Origin Concept</title><author initials="A." surname="Barth"/><date year="2011" month="December"/></front><seriesInfo name="RFC" value="6454"/><seriesInfo name="DOI" value="10.17487/RFC6454"/></reference>
      <reference anchor="RFC7515" target="https://www.rfc-editor.org/info/rfc7515"><front><title>JSON Web Signature (JWS)</title><author initials="M." surname="Jones"/><author initials="J." surname="Bradley"/><author initials="N." surname="Sakimura"/><date year="2015" month="May"/></front><seriesInfo name="RFC" value="7515"/><seriesInfo name="DOI" value="10.17487/RFC7515"/></reference>
      <reference anchor="RFC7638" target="https://www.rfc-editor.org/info/rfc7638"><front><title>JSON Web Key (JWK) Thumbprint</title><author initials="M." surname="Jones"/><author initials="N." surname="Sakimura"/><date year="2015" month="September"/></front><seriesInfo name="RFC" value="7638"/><seriesInfo name="DOI" value="10.17487/RFC7638"/></reference>
      <reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032"><front><title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title><author initials="S." surname="Josefsson"/><author initials="I." surname="Liusvaara"/><date year="2017" month="January"/></front><seriesInfo name="RFC" value="8032"/><seriesInfo name="DOI" value="10.17487/RFC8032"/></reference>
      <reference anchor="RFC8037" target="https://www.rfc-editor.org/info/rfc8037"><front><title>CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JSON Object Signing and Encryption (JOSE)</title><author initials="I." surname="Liusvaara"/><date year="2017" month="January"/></front><seriesInfo name="RFC" value="8037"/><seriesInfo name="DOI" value="10.17487/RFC8037"/></reference>
      <reference anchor="RFC8126" target="https://www.rfc-editor.org/info/rfc8126"><front><title>Guidelines for Writing an IANA Considerations Section in RFCs</title><author initials="M." surname="Cotton"/><author initials="B." surname="Leiba"/><author initials="T." surname="Narten"/><date year="2017" month="June"/></front><seriesInfo name="BCP" value="26"/><seriesInfo name="RFC" value="8126"/><seriesInfo name="DOI" value="10.17487/RFC8126"/></reference>
      <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259"><front><title>The JavaScript Object Notation (JSON) Data Interchange Format</title><author initials="T." surname="Bray" role="editor"/><date year="2017" month="December"/></front><seriesInfo name="STD" value="90"/><seriesInfo name="RFC" value="8259"/><seriesInfo name="DOI" value="10.17487/RFC8259"/></reference>
      <reference anchor="RFC8288" target="https://www.rfc-editor.org/info/rfc8288"><front><title>Web Linking</title><author initials="M." surname="Nottingham"/><date year="2017" month="October"/></front><seriesInfo name="RFC" value="8288"/><seriesInfo name="DOI" value="10.17487/RFC8288"/></reference>
      <reference anchor="RFC8615" target="https://www.rfc-editor.org/info/rfc8615"><front><title>Well-Known Uniform Resource Identifiers (URIs)</title><author initials="M." surname="Nottingham"/><date year="2019" month="May"/></front><seriesInfo name="RFC" value="8615"/><seriesInfo name="DOI" value="10.17487/RFC8615"/></reference>
      <reference anchor="RFC9110" target="https://www.rfc-editor.org/info/rfc9110"><front><title>HTTP Semantics</title><author initials="R." surname="Fielding" role="editor"/><author initials="M." surname="Nottingham" role="editor"/><author initials="J." surname="Reschke" role="editor"/><date year="2022" month="June"/></front><seriesInfo name="STD" value="97"/><seriesInfo name="RFC" value="9110"/><seriesInfo name="DOI" value="10.17487/RFC9110"/></reference>
      <reference anchor="RFC9111" target="https://www.rfc-editor.org/info/rfc9111"><front><title>HTTP Caching</title><author initials="R." surname="Fielding" role="editor"/><author initials="M." surname="Nottingham" role="editor"/><author initials="J." surname="Reschke" role="editor"/><date year="2022" month="June"/></front><seriesInfo name="STD" value="98"/><seriesInfo name="RFC" value="9111"/><seriesInfo name="DOI" value="10.17487/RFC9111"/></reference>
      <reference anchor="RFC9421" target="https://www.rfc-editor.org/info/rfc9421"><front><title>HTTP Message Signatures</title><author initials="A." surname="Backman" role="editor"/><author initials="J." surname="Richer" role="editor"/><author initials="M." surname="Sporny"/><date year="2024" month="February"/></front><seriesInfo name="RFC" value="9421"/><seriesInfo name="DOI" value="10.17487/RFC9421"/></reference>
      <reference anchor="RFC9457" target="https://www.rfc-editor.org/info/rfc9457"><front><title>Problem Details for HTTP APIs</title><author initials="M." surname="Nottingham"/><author initials="E." surname="Wilde"/><author initials="S." surname="Dalal"/><date year="2023" month="July"/></front><seriesInfo name="RFC" value="9457"/><seriesInfo name="DOI" value="10.17487/RFC9457"/></reference>
      <reference anchor="RFC9530" target="https://www.rfc-editor.org/info/rfc9530"><front><title>Digest Fields</title><author initials="R." surname="Polli"/><author initials="L." surname="Pardue"/><date year="2024" month="February"/></front><seriesInfo name="RFC" value="9530"/><seriesInfo name="DOI" value="10.17487/RFC9530"/></reference>
      <reference anchor="RFC9864" target="https://www.rfc-editor.org/info/rfc9864"><front><title>Fully-Specified Algorithms for JOSE and COSE</title><author initials="M." surname="Jones"/><author initials="O." surname="Steele"/><date year="2025" month="October"/></front><seriesInfo name="RFC" value="9864"/><seriesInfo name="DOI" value="10.17487/RFC9864"/></reference>
      <reference anchor="RFC9651" target="https://www.rfc-editor.org/info/rfc9651"><front><title>Structured Field Values for HTTP</title><author initials="M." surname="Nottingham"/><author initials="P-H." surname="Kamp"/><date year="2024" month="September"/></front><seriesInfo name="RFC" value="9651"/><seriesInfo name="DOI" value="10.17487/RFC9651"/></reference>
      <reference anchor="I-D.ietf-webbotauth-httpsig-protocol" target="https://datatracker.ietf.org/doc/draft-ietf-webbotauth-httpsig-protocol/"><front><title>HTTP Message Signatures for automated traffic</title><author initials="T." surname="Meunier"/><author initials="S." surname="Major"/><date year="2026" month="September" day="1"/></front><seriesInfo name="Internet-Draft" value="draft-ietf-webbotauth-httpsig-protocol-00"/></reference>
    </references>
    <references><name>Informative References</name>
      <reference anchor="RFC9205" target="https://www.rfc-editor.org/info/rfc9205"><front><title>Building Protocols with HTTP</title><author initials="M." surname="Nottingham"/><date year="2022" month="June"/></front><seriesInfo name="BCP" value="56"/><seriesInfo name="RFC" value="9205"/><seriesInfo name="DOI" value="10.17487/RFC9205"/></reference>
      <reference anchor="CLOUDFLARE-AI-OPTIONS" target="https://blog.cloudflare.com/content-independence-day-ai-options/"><front><title>Your site, your rules: new AI traffic options for all customers</title><author initials="J.-H." surname="Lee"/><author initials="B." surname="Becker"/><date year="2026" month="July" day="1"/></front></reference>
      <reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942"><front><title>Improving Awareness of Running Code: The Implementation Status Section</title><author initials="Y." surname="Sheffer"/><author initials="A." surname="Farrel"/><date year="2016" month="July"/></front><seriesInfo name="BCP" value="205"/><seriesInfo name="RFC" value="7942"/><seriesInfo name="DOI" value="10.17487/RFC7942"/></reference>
      <reference anchor="RFC9309" target="https://www.rfc-editor.org/info/rfc9309"><front><title>Robots Exclusion Protocol</title><author initials="M." surname="Koster"/><author initials="G." surname="Illyes"/><author initials="H." surname="Zeller"/><author initials="L." surname="Sassman"/><date year="2022" month="September"/></front><seriesInfo name="RFC" value="9309"/><seriesInfo name="DOI" value="10.17487/RFC9309"/></reference>
      <reference anchor="I-D.ietf-aipref-vocab" target="https://datatracker.ietf.org/doc/draft-ietf-aipref-vocab/"><front><title>A Vocabulary for Expressing AI Usage Preferences</title><author initials="P." surname="Keller" role="editor"/><author initials="M." surname="Thomson" role="editor"/><date year="2026"/></front><seriesInfo name="Internet-Draft" value="draft-ietf-aipref-vocab-07"/></reference>
      <reference anchor="I-D.ietf-aipref-attach" target="https://datatracker.ietf.org/doc/draft-ietf-aipref-attach/"><front><title>Associating AI Usage Preferences with Content in HTTP</title><author initials="G." surname="Illyes"/><author initials="M." surname="Thomson"/><date year="2026" month="August"/></front><seriesInfo name="Internet-Draft" value="draft-ietf-aipref-attach-05"/></reference>
      <reference anchor="CONTENT-SIGNALS" target="https://contentsignals.org/"><front><title>Content Signals Policy</title><author><organization>Content Signals</organization></author><date year="2025"/></front></reference>
      <reference anchor="TERMS-TXT-IMPL" target="https://doi.org/10.5281/zenodo.22647915"><front><title>terms.txt v0.1: reference implementation and benchmark results</title><author initials="R." surname="Chowdhury"/><date year="2026" month="September" day="10"/></front><seriesInfo name="DOI" value="10.5281/zenodo.22647915"/></reference>
    </references>
  </references>

  <section anchor="example-exchange"><name>Complete Example Exchange</name>
    <t>A user-delegated agent operated by https://bot.example requests a resource under /premium/ at origin.example, whose terms are those of <xref target="example-file"/>. Line breaks in field values are for presentation only.</t>
    <artwork type="text"><![CDATA[
GET /premium/1 HTTP/1.1
Host: origin.example
Signature-Agent: sig1="https://bot.example"
Signature-Input: sig1=("@method" "@target-uri"
  "signature-agent";key="sig1" "access-intent" "access-delegation"
  "access-payment");created=1789000000;expires=1789000280;
  nonce="Yw3f...";keyid="poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U";
  tag="web-bot-auth"
Signature: sig1=:RdNF...:
Access-Intent: purpose="agent", use="reference"
Access-Delegation: eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiLi4uIn0.eyJpc3Mi...
Access-Payment: voucher eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiLi4uIn0.ey...
]]></artwork>
    <t>Had the request carried no voucher, the origin would have answered:</t>
    <artwork type="text"><![CDATA[
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Cache-Control: no-store
Link: </.well-known/terms.txt>; rel="access-terms"

{"type":
   "https://iana.org/assignments/http-problem-types#payment-required",
 "title":"Payment required by access terms","status":403,
 "terms_id":"2026-09-01","purpose":"agent",
 "price":{"amount":"0.01","currency":"USD","unit":"request"},
 "payment":[{"method":"voucher",
   "settlement":"https://settle.example/.well-known/settlement"}],
 "terms":"/.well-known/terms.txt"}
]]></artwork>
    <t>With a valid voucher, the origin serves the resource:</t>
    <artwork type="text"><![CDATA[
HTTP/1.1 200 OK
Content-Type: text/html
Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
Cache-Control: no-store
Link: </.well-known/terms.txt>; rel="access-terms"
Access-Receipt: eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiLi4uIn0.eyJpc3MiOiJv...

<html>...</html>
]]></artwork>
    <t>The receipt payload, decoded:</t>
    <artwork type="text"><![CDATA[
{"iss":"origin.example","kid":"...",
 "agent":
   "https://bot.example/.well-known/http-message-signatures-directory",
 "sub":"3kqJ...","purpose":"agent","use":"reference",
 "terms_id":"2026-09-01","terms_digest":"uU0n...",
 "method":"GET","target":"https://origin.example/premium/1",
 "status":200,"content_digest":"sha-256=:X48E...:",
 "req":"n4bQ...","ts":1789000001,"id":"9f1c..."}
]]></artwork>
  </section>

  <section anchor="ack" numbered="false"><name>Acknowledgments</name>
    <t>This document composes work by the authors of HTTP Message Signatures, Web Bot Auth, AI Preferences, and the Content Signals convention, and draws on measurements published by Cloudflare, Imperva, the Pew Research Center, and the Data Provenance Initiative. The enforcement boundary in <xref target="scope"/> and the replay ordering in <xref target="origin-processing"/> were sharpened by review of an earlier version of the reference implementation.</t>
  </section>
</back>
</rfc>
