<?xml version="1.0" encoding="UTF-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" version="3" ipr="trust200902" category="exp" submissionType="IETF" docName="draft-dierken-usage-log-http-00" xml:lang="en">
  <front>
    <title abbrev="HTTP Usage Reporting">HTTP Usage Reporting for Cached Resources</title>
    <author fullname="S. Mike Dierken" initials="M." surname="Dierken">
      <organization>paywalls.net</organization>
      <address>
        <email>mike@paywalls.net</email>
      </address>
    </author>
    <date year="2026" month="March" day="17"/>
    <area>ART</area>
    <keyword>HTTP</keyword>
    <keyword>usage reporting</keyword>
    <keyword>caching</keyword>
    <keyword>automation</keyword>
    <keyword>AI agents</keyword>
    <abstract>
      <t>This document defines a mechanism by which an HTTP origin can advertise an endpoint for downstream usage reporting and by which an authenticated client operator can report usage of cached representations that were used without issuing additional requests to the origin.</t>
      <t>The mechanism complements access-time response metadata by allowing a client operator to report downstream usage associated with a prior origin-served response context. The protocol defines discovery of a usage reporting endpoint, submission semantics, and a minimal record format suitable for reconciliation and billing.</t>
      <t>This specification does not define payment, settlement, or enforcement mechanisms. It defines a good-faith accounting protocol for reporting downstream usage.</t>
    </abstract>
  </front>

  <middle>
    <section numbered="true" toc="default">
      <name>Status of This Memo</name>
      <t>This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.</t>
      <t>Internet-Drafts are working documents of the Internet Engineering Task Force (IETF).</t>
    </section>

    <section numbered="true" toc="default">
      <name>Introduction</name>
      <t>Some HTTP resources may be served from cache or otherwise reused without an additional request to the origin. In such cases, the origin may not directly observe every downstream use of the representation.</t>
      <t>This document defines a mechanism for reporting such usage back to the origin.</t>
      <t>The goals of this specification are to:</t>
      <ul spacing="normal">
        <li>allow an origin to advertise a usage reporting endpoint,</li>
        <li>allow authenticated client operators to report downstream usage,</li>
        <li>support both per-event and aggregated usage reporting, and</li>
        <li>provide sufficient structure for reconciliation and billing.</li>
      </ul>
      <t>This document does not define commercial models, payment systems, or enforcement mechanisms for dishonest reporting.</t>
      <t>The trust model assumed by this protocol is that authenticated client operators submit usage reports in good faith and that the origin performs reconciliation and optional deduplication.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Terminology</name>
      <dl newline="false" spacing="normal">
        <dt>Origin</dt>
        <dd>The server that served the response or its delegated reporting service.</dd>
        <dt>Client Operator</dt>
        <dd>The authenticated entity responsible for requesting resources and reporting downstream usage.</dd>
        <dt>Cached Representation</dt>
        <dd>A representation used without issuing a new request to the origin.</dd>
        <dt>Usage Report</dt>
        <dd>A batch submission containing one or more usage records.</dd>
        <dt>Usage Record</dt>
        <dd>A single assertion of downstream usage.</dd>
        <dt>Response Identifier</dt>
        <dd>An identifier associated with a prior origin-served response context.</dd>
      </dl>
    </section>

    <section numbered="true" toc="default">
      <name>Usage Key</name>
      <t>The accounting identity for reported usage in this specification is the tuple:</t>
      <sourcecode><![CDATA[
(resource, response_id)
]]></sourcecode>
      <t>where <tt>resource</tt> identifies the URI of the representation used and <tt>response_id</tt> identifies the origin-served response context associated with that representation.</t>
      <t>The <tt>response_id</tt> ties the reported usage to the representation version, access event, or other origin-defined response context previously recorded by the origin.</t>
      <t>All usage records reported by this protocol refer to exactly one usage key.</t>
      <t>A <tt>response_id</tt> value is assigned by the origin or its delegated service. Clients MUST NOT invent substitute values when none was provided.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Protocol Overview</name>
      <t>The mechanism consists of two parts:</t>
      <ol spacing="normal">
        <li>discovery of a usage reporting endpoint, and</li>
        <li>submission of usage reports.</li>
      </ol>
      <t>A typical interaction proceeds as follows:</t>
      <ol spacing="normal">
        <li>The origin serves a response and advertises a usage reporting endpoint.</li>
        <li>The client operator later reuses the cached representation without contacting the origin.</li>
        <li>The client operator periodically submits usage reports describing downstream usage.</li>
      </ol>
      <t>Usage reports are submitted using HTTP POST and may contain either individual usage events or aggregated usage records.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Discovery</name>
      <t>An origin MAY advertise a usage reporting endpoint using the HTTP <tt>Link</tt> response header with relation type <tt>usage-log</tt>.</t>
      <t>Example:</t>
      <sourcecode type="http"><![CDATA[
Link: <https://example.com/usage-log>; rel="usage-log"
]]></sourcecode>
      <t>The target URI identifies the endpoint that accepts usage reports.</t>
      <t>An origin MAY include this header on any response relevant to future cached use.</t>

      <section numbered="true" toc="default">
        <name>Authoritative Discovery</name>
        <t>Resource-associated discovery via the <tt>Link</tt> header is authoritative.</t>
        <t>If multiple discovery mechanisms exist, the <tt>usage-log</tt> link associated with the resource response takes precedence.</t>
      </section>

      <section numbered="true" toc="default">
        <name>Optional Default Discovery</name>
        <t>Deployments MAY expose a default usage reporting endpoint via a well-known resource or equivalent mechanism.</t>
        <t>Such mechanisms are secondary to resource-associated discovery and are outside the scope of this specification.</t>
      </section>
    </section>

    <section numbered="true" toc="default">
      <name>Submission</name>
      <t>Usage reports are submitted via HTTP POST to the advertised usage reporting endpoint.</t>
      <t>Clients MUST authenticate using an origin-supported HTTP authentication mechanism.</t>
      <t>Example:</t>
      <sourcecode type="http"><![CDATA[
POST /usage-log HTTP/1.1
Host: example.com
Authorization: Bearer agt_XYZ
Content-Type: application/usage-report+jsonl
]]></sourcecode>
      <t>The request body contains one or more usage records encoded as JSON Lines.</t>
      <t>Each line is an independent JSON object.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Media Type</name>
      <t>This specification defines the media type <tt>application/usage-report+jsonl</tt>.</t>
      <t>Encoding is UTF-8 line-delimited JSON objects. Each line represents one usage record.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Usage Record Format</name>
      <t>Two reporting forms are defined.</t>

      <section numbered="true" toc="default">
        <name>Event Form</name>
        <t>In event form, each record represents one usage event.</t>
        <t>Fields:</t>
        <ul spacing="normal">
          <li><tt>resource</tt> -- string; URI of the resource used</li>
          <li><tt>response_id</tt> -- string; identifier of the associated origin-served response context</li>
          <li><tt>used_at</tt> -- timestamp in RFC 3339 format</li>
        </ul>
        <t>Example:</t>
        <sourcecode type="json"><![CDATA[
{"resource":"https://example.com/news/123","response_id":"resp_82fd","used_at":"2026-03-06T18:05:00Z"}
]]></sourcecode>
      </section>

      <section numbered="true" toc="default">
        <name>Aggregate Form</name>
        <t>In aggregate form, a record summarizes multiple usage events for the same usage key over a reporting window.</t>
        <t>Fields:</t>
        <ul spacing="normal">
          <li><tt>resource</tt> -- string</li>
          <li><tt>response_id</tt> -- string</li>
          <li><tt>window_start</tt> -- timestamp in RFC 3339 format</li>
          <li><tt>window_end</tt> -- timestamp in RFC 3339 format</li>
          <li><tt>count</tt> -- integer</li>
        </ul>
        <t>Example:</t>
        <sourcecode type="json"><![CDATA[
{"resource":"https://example.com/news/123","response_id":"resp_82fd","window_start":"2026-03-06T00:00:00Z","window_end":"2026-03-07T00:00:00Z","count":148}
]]></sourcecode>
        <t>Aggregation of identical usage keys is optional but RECOMMENDED.</t>
      </section>
    </section>

    <section numbered="true" toc="default">
      <name>Client Requirements</name>
      <t>A client operator submitting usage reports:</t>
      <ul spacing="normal">
        <li>MUST authenticate to the usage reporting endpoint,</li>
        <li>MUST ensure that submitted records represent good-faith assertions of usage,</li>
        <li>SHOULD batch records when practical,</li>
        <li>SHOULD aggregate usage where appropriate, and</li>
        <li>SHOULD retain internal records sufficient for reconciliation.</li>
      </ul>
      <t>Reports MAY be submitted asynchronously and out of chronological order.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Origin Requirements</name>
      <t>An origin receiving usage reports:</t>
      <ul spacing="normal">
        <li>MUST authenticate the sender,</li>
        <li>MUST treat accepted reports as operator assertions of usage,</li>
        <li>SHOULD tolerate accidental duplicate submission,</li>
        <li>MAY deduplicate records using deployment-specific methods, and</li>
        <li>MAY reject malformed reports.</li>
      </ul>
      <t>This specification does not require exactly-once delivery semantics.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Response Semantics</name>
      <t>Typical responses include:</t>
      <dl newline="false" spacing="normal">
        <dt>202</dt>
        <dd>report accepted for processing</dd>
        <dt>200</dt>
        <dd>report accepted and processed</dd>
        <dt>400</dt>
        <dd>malformed report</dd>
        <dt>401 or 403</dt>
        <dd>authentication or authorization failure</dd>
        <dt>413</dt>
        <dd>report batch too large</dd>
        <dt>415</dt>
        <dd>unsupported media type</dd>
        <dt>429</dt>
        <dd>sender should slow down</dd>
        <dt>5xx</dt>
        <dd>server error; client MAY retry</dd>
      </dl>
      <t><tt>202 Accepted</tt> is RECOMMENDED for asynchronous ingestion systems.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Relationship to Access-Time Response Metadata</name>
      <t>This specification complements, but does not replace, access-time response metadata.</t>
      <t>Access-time metadata describes the terms or context under which a response was served by the origin.</t>
      <t>Usage reporting describes downstream usage that occurred after access without a new origin request.</t>
      <t>How reported usage maps to pricing, licensing, or billing terms is outside the scope of this specification.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Duplicate Submission</name>
      <t>Duplicate submission is considered an operational concern rather than a core protocol threat.</t>
      <t>Usage reports create obligations for the reporting operator; therefore strict anti-replay protocols are not required.</t>
      <t>Origins SHOULD implement reconciliation or duplicate suppression sufficient for normal operational reliability.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Security Considerations</name>
      <t>Usage reports may create accounting or billing consequences. Origins MUST authenticate reporting clients.</t>
      <t>Implementations SHOULD use HTTPS transport.</t>
      <t>Implementations MAY apply additional integrity protections such as HTTP Message Signatures if required for dispute resolution.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Privacy Considerations</name>
      <t>Usage reports may expose resource access patterns.</t>
      <t>Deployments SHOULD avoid including user-level identifiers unless strictly necessary.</t>
      <t>Usage reporting SHOULD identify resources and operator-level usage without exposing individual user data.</t>
    </section>

    <section numbered="true" toc="default">
      <name>Link Relation Registration</name>
      <t>Relation Name: <tt>usage-log</tt></t>
      <t>Description: identifies an endpoint that accepts usage reports for downstream usage of origin resources or cached representations.</t>
      <t>Reference: this document.</t>
    </section>

    <section numbered="true" toc="default">
      <name>IANA Considerations</name>
      <t>This document requests registration of:</t>
      <ul spacing="normal">
        <li>the <tt>usage-log</tt> link relation</li>
        <li>the media type <tt>application/usage-report+jsonl</tt></li>
        <li><tt>Response-Id</tt></li>
      </ul>
    </section>

    <section numbered="true" toc="default">
      <name>Example</name>
      <t>Origin response:</t>
      <sourcecode type="http"><![CDATA[
HTTP/1.1 200 OK
Response-Id: resp_82fd
Link: <https://example.com/usage-log>; rel="usage-log"
Cache-Control: max-age=86400
]]></sourcecode>
      <t>Later, the client submits a daily aggregate usage report:</t>
      <sourcecode type="http"><![CDATA[
POST /usage-log HTTP/1.1
Host: example.com
Authorization: Bearer agt_XYZ
Content-Type: application/usage-report+jsonl
]]></sourcecode>
      <sourcecode type="json"><![CDATA[
{"resource":"https://example.com/news/123","response_id":"resp_82fd","window_start":"2026-03-06T00:00:00Z","window_end":"2026-03-07T00:00:00Z","count":148}
]]></sourcecode>
      <t>The origin acknowledges receipt:</t>
      <sourcecode type="http"><![CDATA[
HTTP/1.1 202 Accepted
]]></sourcecode>
    </section>
  </middle>
</rfc>
