Terms in the 402: The Payment Challenge That Also Tells You What You're Licensed To Do
written by Stefan Christoph
- 6 minutes readLink: rel="license" header) and a CoMP-style usage declaration at a well-known URI. An agent declares its intended use, reads the terms, refuses the uses the license prohibits, pays for the ones it permits, and gets the content. The whole thing runs locally with zero dependencies, and the code is on GitHub.Where the last post left off
Part 4 made a layered argument: HTTP plus x402 handle delivery and payment, while RSL and the IAB’s CoMP handle terms — what an agent is licensed to do with the bytes after it pays. The two are complementary, and the interesting move is to put them on one origin so the 402 that charges an agent also tells it what the purchase licenses.
That’s a claim worth building. So I built the smallest thing that demonstrates it: a publisher that serves one gated article, returns a 402 with terms attached, and hands over content once a (simulated) payment arrives. The code is at github.com/stechr/schristoph-blog-samples/tree/main/terms-in-the-402 [5]. Python standard library only, no dependencies, runs on 127.0.0.1.
The flow
The flow: the 402 carries both a price (x402) and a terms pointer (RSL license + CoMP usage doc). The agent reads terms before paying.
Nothing here needs a second API surface. It’s the ordinary website, answering a 402 with a slightly richer body than “insufficient funds.”
What the 402 actually carries
This is the whole point, so here is a real response from the running server. The agent asked for the article declaring X-Intended-Function: ai-input / X-Intended-Subfunction: rag (a RAG grounding fetch):
# HTTP/1.0 402 Payment Required (headers)
Link: <http://127.0.0.1:8402/license.xml>; rel="license"
License: http://127.0.0.1:8402/license.xml
X-Usage-Declaration: http://127.0.0.1:8402/.well-known/usage.json
Cache-Control: no-store
{
"x402Version": 2,
"error": "payment required",
"accepts": [
{ "scheme": "exact", "network": "eip155:8453", "asset": "USDC",
"amount": "0.010", "unit": "per-use", "resource": "/articles/meridian-fx-outlook",
"maxTimeoutSeconds": 120 }
],
"terms": {
"publisher": "The Meridian",
"licenseUrl": "http://127.0.0.1:8402/license.xml",
"usageUrl": "http://127.0.0.1:8402/.well-known/usage.json",
"reportUrl": "http://127.0.0.1:8402/usage-report",
"function": "ai-input", "subFunction": "rag",
"citationRequired": true
}
}
Two halves in one response. The accepts[] array is the payment challenge: the x402 shape a facilitator or an edge feature like AWS WAF’s Monetize action would verify [1]. The terms{} block, plus the Link: rel="license" header, is the part a bare 402 omits: a pointer to what the purchase licenses.
The license the 402 points at
The Link: rel="license" header is how RSL associates terms with a resource over HTTP [2]. Follow it and you get a per-URL declaration of permitted and prohibited uses:
<rsl xmlns="https://rslstandard.org/rsl">
<content url="http://127.0.0.1:8402/articles/meridian-fx-outlook">
<license>
<permits type="usage">ai-input</permits>
<permits type="usage">ai-index</permits>
<prohibits type="usage">ai-train</prohibits>
<payment type="pay-per-inference"><amount currency="USDC">0.010</amount></payment>
<attribution required="true"/>
</license>
</content>
</rsl>
Now the interesting case. If the agent declares ai-train, the server still quotes a training price, but the RSL license prohibits training. A well-behaved agent reads that and declines to pay:
[agent] declaring intended use: ai-train/training
[agent] <- 402
[agent] fetched license (200): permits=2 prohibits=1
[agent] STOP: license PROHIBITS ai-train; not paying.
That’s the behavior you can’t get from price alone. The 402 didn’t just gate access. It let the agent make a rights decision before spending a cent.
Mapping to the CoMP vocabulary
The well-known usage document (/.well-known/usage.json) is a CoMP-style offer sheet [3]. CoMP models the machine-readable offer (a licenseurl, a reporturl, a pricing basis, and an intended-use function vocabulary) while declaring payment and clearing out of scope. The demo’s usage vocabulary maps straight onto it:
| Declared use | CoMP function / subFunction | Demo price (fictional) | License |
|---|---|---|---|
| RAG grounding | ai-input / rag | 0.010 USDC per-use | permitted |
| Grounding | ai-input / grounding | 0.010 USDC per-use | permitted |
| Agent actions | ai-index / agent-actions | 0.020 USDC per-query | permitted |
| Training | ai-train / training | 0.250 USDC per-token-batch | prohibited |
Same content, different price by declared intent, and one use the publisher simply won’t sell at any price. That per-use tiering is where CoMP’s function vocabulary earns its keep: it gives the 402 a shared language for why the price differs, not just what it is. CoMP leaves the money to x402; x402 leaves the terms to CoMP and RSL; the demo puts both in one exchange.
What’s real and what’s simulated
Honesty matters more than a slick demo. Real: the HTTP flow, the header and JSON shapes, the per-use pricing, and the license-driven refusal. Simulated: payment verification. The server accepts any well-formed X-Payment header whose decoded amount clears the quote — there are no keys, no chain, and no funds move. A production edge (WAF Monetize or an x402 facilitator) verifies a signed payment authorization on-chain [1]. The point of the demo is the terms travelling with the 402, not the settlement.
Two more details I kept because they matter at scale: the agent’s simulated payment carries a paymentIdentifier (an idempotency key, so a retry doesn’t double-settle), and the paid response is Cache-Control: no-store (a paid response must not leak from a shared cache). Both are small, both are easy to forget, and both bite in production.
Why this is the useful middle layer
The previous post predicted a hybrid end-state [4]: edge-enforced 402/x402 for anonymous access, a terms layer the 402 points at, and marketplaces for bulk deals. This demo is that middle layer, made concrete on the smallest possible surface. It doesn’t need a marketplace or a vector-search API to show the idea. A publisher can start by making its existing 402 answer one extra question: what am I allowed to do with this?
If you’re running this on AWS
The demo simulates the edge 402 so it stays dependency-free and public. On AWS the payment half is a managed feature: AWS WAF AI traffic monetization returns the 402 with pricing and verifies the signed payment at the CloudFront edge [1]. The terms half is just static content you already know how to serve: the RSL license.xml and the CoMP-style usage.json behind the same distribution, with the Link: rel="license" header added to the monetized responses. No new operated surface: the terms ride along on the origin you already have.
Clone it, run python3 server.py, point agent.py at it, and watch a 402 hand over both a price and a permission. Then tell me: as an agent author, would you actually honor a prohibits you could technically ignore, or does that only work with enforcement behind it?
Sources
- [1] AWS WAF AI traffic monetization —
Monetizeaction returns HTTP 402 with pricing and verifies the signed payment at the edge. - [2] Really Simple Licensing (RSL) — per-URL license terms, associable via robots.txt
License:, HTTPLinkheader, HTML, or RSS. - [3] IAB Tech Lab CoMP 1.0 specification — offer/usage object model, intended-use function vocabulary,
licenseurl/reporturl; payment out of scope. - [4] Why Doesn’t the Web Just Use HTTP? (Part 4) — the layer map this build sits in.
- [5] terms-in-the-402 — the code
About the Author
Stefan Christoph is a Principal Solutions Architect at AWS, focused on agentic AI, media & entertainment, and helping builders move from demo to production. He writes about AI architecture, developer productivity, and the future of software.
This is a personal blog. Opinions expressed here are my own and do not represent the views or positions of my employer.
🎬 Also available as a blog walkthrough video on YouTube
❤️ Created with the support of AI (Kiro)
📝 Last updated: August 17, 2026 — Editorial polish for readability and voice