fair-meter: the Fair Offer kit for x402 sellers
What a seller needs to keep the Fair Offer Standard 0.4, in one small Python package with no required dependencies:
| Module | Rule | What it does |
|---|---|---|
fair_meter.declare |
FO-2 to FO-10 | Builds the fair-offer block for your 402, refusing anything the 0.4 schema doesn't allow. |
fair_meter.meter |
FO-9 | The charge under the buyer's ceiling with x402's upto: units times one public unit price, never more than the ceiling, nothing when nothing was delivered. |
fair_meter.receipt |
FO-3 | A receipt bound to the SHA-256 of the RFC 8785 form of the result, signed with an EVM key (EIP-191). |
fair_meter.guard |
FO-6 | Finds text that reads as an instruction to the buying agent in any string of a response, however it is hidden. |
fair_meter.ledger |
FO-10 | A receipts ledger that only grows, one Merkle root a month, a proof per receipt. |
fair_meter.pledge |
FO-7 | A public share paid once a month: the pledge ledger page (the standard's schema) from the receipts ledger, with each month's standing under the small-sums rule. |
fair_meter.jcs |
RFC 8785, the canonical JSON the delivery hash is taken over. |
Signing receipts needs eth-account, which the x402 SDK already installs. Licence: Apache-2.0 (the standard's
text, schema and examples in the rest of this repository are CC BY 4.0).
Install
From this repository until it is published:
pip install "git+https://github.com/Agoranome/fair-offer.git#subdirectory=kit"
A metered route with the x402 SDK (Python, 2.25)
Register x402's upto scheme beside exact (the facilitator must list upto on your network), offer the metered
route with both, and declare the block:
from x402.mechanisms.evm.exact import ExactEvmServerScheme
from x402.mechanisms.evm.upto import UptoEvmServerScheme
from fair_meter import declare
server.register(NETWORK, ExactEvmServerScheme())
server.register(NETWORK, UptoEvmServerScheme())
BLOCK = declare.extension(declare.block(
signer=RECEIPT_ADDRESS, # the address that signs receipts
sample="/v1/rows/sample",
meter=declare.metered("row", "0.0002"), # one public price a row (FO-9)
ledger="/receipts/ledger", reports=None, # the open book (FO-10)
))
# On the route's config: both options at the same price (for upto it is the ceiling), and extensions=BLOCK.
In the handler, guard the result, settle only what was delivered, sign the receipt and put it in the book once the payment settles:
from fair_meter import guard, meter, receipt
UNIT = meter.unit_atomic("0.0002") # 200 units of USDC
async def rows(request):
requirements = request.state.payment_requirements
found = guard.guard(lookup(request)) # FO-6: refuse to send instructions; the failed call isn't settled
charged = len(found["rows"]) * UNIT
if requirements.scheme == "upto":
charged = meter.charge(len(found["rows"]), UNIT, int(requirements.amount))
paid = receipt.build(receipt_id=new_id(), resource=str(request.url), network=requirements.network,
asset=requirements.asset, pay_to=requirements.pay_to, amount_atomic=charged,
result=found, ceiling_atomic=int(requirements.amount), units=len(found["rows"]),
unit="row")
response = JSONResponse(receipt.attach(found, paid, RECEIPT_KEY))
if requirements.scheme == "upto":
name, value = meter.overrides(charged) # the middleware settles this amount, never the ceiling
response.headers[name] = value
return response
When the facilitator returns the settlement, record it: book.record(receipt_id, payer=..., amount_atomic=..., tx_hash=...), and serve book.view() at your ledger path and book.proof(receipt_id) beside it. A metered call
that charged nothing has no transaction and stays out of the book.
Read the field names on requirements from your SDK version; the shape above is the 2.25 Python SDK's.
A public share (FO-7)
If you promise a share of what you earn to a cause, publish the pledge ledger beside the receipts ledger:
from fair_meter import pledge
page = pledge.ledger_doc(book, share_bps=1500, proof_url="https://you.example/receipts/{receipt_id}/proof",
recipient=CAUSE, transfers={"2026-11": [{"tx_hash": "0x...", "amount_atomic": 300000}]})
Each month shows its root, its basis, what it owes (the share, rounded up), what was sent and its standing: a month
that owes under $1 carries over and shows as owed, and nothing is carried past the end of a quarter (carry-1).
Send one USDC transfer on Base to the recipient each month; anyone can read it on the chain.
What a buyer checks
receipt.verify(body)(or any EIP-191 library over the receipt's RFC 8785 bytes): the receipt is signed by its signer and names the hash of the result it came with.agoranome-inspector check-delivery answer.jsonrecomputes the delivery hash with no trust in the seller.- The ledger's month roots fold every receipt's proof; Agoranome's inspector can copy them into its open book
(
anchor-lab) so a past month can't be changed quietly (verify-receipt). https://api.agoranome.com/v1/fair-offer/check?url=reads your live 402 against your block, free.
Tests
cd kit && pip install -e ".[test]" && pytest
The ledger's roots are tested against the construction Agoranome's lab ledger uses, so the same tools check both.
Metadata
Release files for fair-meter 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fair_meter-0.2.0.tar.gz | 24.1 kB | With provenance | Details for fair_meter-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fair_meter-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for fair_meter-0.2.0-py3-none-any.whl |
Total release size: 48.2 kB
Release files / fair_meter-0.2.0.tar.gz
| Download URL | fair_meter-0.2.0.tar.gz |
|---|---|
| Size | 24.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
13b5cef1436b834e70d554c2bf16087e66c95ce134e9ed389ddce30a36a8a5d7
|
|
BLAKE2b-256 checksum How to use checksums |
ab1dbe5bdc13f2271af45e6ce599d61912547af229952d71c2bcb50e7cdd9347
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / fair_meter-0.2.0-py3-none-any.whl
| Download URL | fair_meter-0.2.0-py3-none-any.whl |
|---|---|
| Size | 24.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a2b69247566d74d9f4c19522a983450d1144e9cad3e9702c9565801892e73117
|
|
BLAKE2b-256 checksum How to use checksums |
50e56eb161f3e24120d9223daaf001b9c015160fdd0c208bdbb0ad8ea5b86113
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logSecurity for fair-meter 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for fair_meter-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.