Skip to main content

payperbyte-sdk — PayPerByte Python SDK

Python SDK for PayPerByte — the cryptographically attested, provenance-verifiable data layer for AI agents. Discover first-party feeds, pay per call, subscribe, stream payloads, and verify every payload against its EIP-712 attestation (authenticity + tamper-evidence — who signed these exact bytes — not a correctness guarantee). No token; x402 USDC payments settle on Base mainnet (the on-chain subscribe + EIP-712 attestation rail is Arbitrum Sepolia, testnet, pre-audit).

Installation

pip install payperbyte-sdk

Keyless x402 pay-per-call support (the GatewayClient) needs the optional x402 stack:

pip install "payperbyte-sdk[x402]"

Quick Start

from eth_account import Account
from byte import (
    Publisher,
    Subscriber,
    Mercat,
    GatewayClient,
    verify_payload,
    HashMismatchError,
    CanonicalFormMismatchError,
    ARBITRUM_SEPOLIA,
)

# 1. Discover — browse first-party feeds via the keyless x402 gateway catalog.
gw = GatewayClient(account=Account.from_key("0x..."))   # a wallet, NOT an API key
catalog = gw.discover()                                  # GET /feeds
for feed in catalog["feeds"]:
    print(feed["id"], feed["price"], feed["provenance"])

# Or discover publishers via the indexer (Mercat).
mercat = Mercat(ARBITRUM_SEPOLIA.indexer_url)
publishers = await mercat.search(topic="eth-price")

# 2. Subscribe — register in the social registry and approve DataStream to pull
#    per-message fees directly. No escrow, no deposit: your USDC stays in your
#    wallet until a message is actually settled. allowance_usdc is a 6-decimal
#    spend ceiling sized to cover the fees you expect to pay.
#    (This leg is on Arbitrum Sepolia — testnet, pre-audit.)
subscriber = Subscriber("0x...private_key...", ARBITRUM_SEPOLIA)
subscriber.subscribe(publishers[0]["address"], allowance_usdc=10.0)

# 3. Stream — receive payload events as the publisher broadcasts.
async for msg in subscriber.stream():
    payload = fetch_from_my_archive(msg["payload_hash"])

    # 4. Verify — keccak256 of the EXACT delivered bytes vs the attested hash.
    #    Throws HashMismatchError if the bytes don't match what was attested.
    try:
        verify_payload(payload, msg["payload_hash"])
    except HashMismatchError:
        continue  # do NOT consume mismatched bytes
    consume(payload)

Keyless x402 (pay-per-call)

The GatewayClient mirrors the PayPerByte x402 gateway. It is keyless: a wallet signs the payment (EIP-3009 transferWithAuthorization, gasless — the facilitator broadcasts and pays gas), settled in USDC on Base mainnet. There is no API key anywhere.

from eth_account import Account
from byte import GatewayClient

gw = GatewayClient(account=Account.from_key("0x..."))    # defaults to https://x402.payperbyte.io
result = gw.fetch_feed("weather")                        # GET -> 402 -> sign USDC -> retry -> data
print(result["data"])
print(result["settlement"])        # {"success", "payer", "transaction"} (on-chain settle tx) or None
print(result["disclaimerCategory"])

Verdict oracles are POST feeds that take a JSON body and answer BEFORE you act — a signed ALLOW/WARN/BLOCK with an embedded EIP-712 receipt over the exact answer bytes:

result = gw.fetch_feed("address-reputation", body={
    "domain": "example.com",                              # the payee's web domain
    "address": "0x1111111111111111111111111111111111111111",  # receiving address
    "chain": "base",
})
# result["data"]["answer"]["verdict"]  -> "ALLOW" | "WARN" | "BLOCK"
# result["data"]["attestation"]        -> EIP-712 receipt: recompute keccak256(answer),
#                                         recover the signer, THEN act

(pkg-verdict does the same for software packages.) The verdict is a screening signal — the receipt proves who signed these exact bytes, not that the verdict is correct.

Two distinct USDC flows. The on-chain settlement leg (Subscriber.subscribe → register in DataRegistry + approve DataStream as a direct USDC spender, Arbitrum Sepolia) is independent of the x402 gateway payment (GatewayClient → EIP-3009 USDC on Base at fetch time). Pay-per-call feeds need only the x402 leg.

Features

  • Feed discovery — browse the x402 gateway catalog (GatewayClient.discover) or search publishers via the indexer (Mercat)
  • Subscription management — subscribe, unsubscribe, check status (direct-allowance USDC settlement; the SDK approves DataStream as a direct spender)
  • Data streaming — publish and receive payloads via DataStream
  • Payload verification — byte-exact keccak256 against the EIP-712 attested hash, plus a form-aware archive path that fails closed (CanonicalFormMismatchError) instead of raising a tamper alarm it cannot prove
  • Keyless x402 — pay-per-call feed access with a wallet (EIP-3009, USDC on Base), no API key
  • Provenance — read publisher status, subscriber/message counts, and revenue from the on-chain registry

Network Support

Network Chain ID Role Status
Base 8453 x402 USDC payment settlement (GatewayClient) Live (mainnet)
Arbitrum Sepolia 421614 On-chain subscribe + EIP-712 attestation anchor Live (testnet, pre-audit)
Arbitrum One 42161 Attestation mainnet re-anchor Planned (audit-gated)

PayPerByte contracts

PayPerByte is a lean 3-contract core. No token; all settlement is in external USDC. Subscriptions are a direct ERC-20 allowance — there is no escrow contract. A subscriber registers in DataRegistry and grants DataStream a USDC allowance; DataStream pulls the exact per-message fee with transferFrom at publish time, so funds stay in the subscriber's wallet until a message is settled. Each payload carries an EIP-712 PayloadAttestation so subscribers can confirm exactly what they received and from whom.

Contract Role
DataRegistry Publisher registration; subscriber social registry (subscribe / unsubscribe / isSubscribed)
DataStream Per-message payload settlement; pulls fees via direct USDC allowance
SchemaRegistry Feed schema + methodology references

Contract and settlement-USDC addresses are resolved per-network by the SDK (ARBITRUM_SEPOLIA, LOCAL_ANVIL).

Canonical payload bytes — two forms, and why byte-exact verification wins

The primary verify path is byte-exact: hash the exact bytes you received (verify_payload) against the attested hash. That path needs no canonicalization at all and is the strongest tamper evidence the SDK offers. Prefer it whenever you hold the delivered bytes.

Canonicalization only enters when a payload is re-serialized (e.g. re-deriving bytes from a parsed archive envelope) — and the stack has two canonical-JSON forms there, not one:

  • SDK publish path (byte.canonical): recursively key-sorted, no whitespace, ensure_ascii=False. Matches the TypeScript SDK for payloads that keep values to strings/bools/ints; floats, huge ints, and non-BMP keys are explicitly out of scope (this is NOT full RFC 8785/JCS).
  • First-party live feeds (data-feeds): INSERTION-ORDER compact JSON — a frozen hash-compatibility surface that must never be re-sorted.

A payload signed under one form will not hash-match a re-derivation under the other, so fetch_and_verify is form-aware: it tries the raw response bytes and every known form, and if none reproduces the attested hash it raises CanonicalFormMismatchError — deliberately NOT HashMismatchError, because a failed re-serialization cannot distinguish tampering from a form mismatch. Fail closed either way: don't consume the payload; fetch the exact delivered bytes and use byte-exact verify_payload.

Modules

  • ByteClient — low-level client holding the web3 contract instances (used by Publisher/Subscriber)
  • Publisher — register a feed, publish data, sign EIP-712 PayloadAttestations
  • Subscriber — subscribe (register in DataRegistry + approve DataStream as a direct USDC spender), receive payloads, stream events
  • GatewayClient — keyless x402 pay-per-call client (a wallet, not an API key)
  • verify_payload / verify_event_payload — byte-exact payload verification against attestations
  • fetch_and_verify — archive fetch + form-aware verification (fails closed with CanonicalFormMismatchError)
  • Mercat — feed search and discovery (connects to the indexer API)

Related

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

payperbyte_sdk-0.2.0.tar.gz (37.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

payperbyte_sdk-0.2.0-py3-none-any.whl (34.3 kB view details)

Uploaded Python 3

File details

Details for the file payperbyte_sdk-0.2.0.tar.gz.

File metadata

  • Download URL: payperbyte_sdk-0.2.0.tar.gz
  • Upload date:
  • Size: 37.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for payperbyte_sdk-0.2.0.tar.gz
Algorithm Hash digest
SHA256 47a641a98574255b058f5ac77dda9ec0df305bc9c3112e9edc57a65a08319153
MD5 14c1ee81ea162fb9b8eded4c4d4587e2
BLAKE2b-256 80a70f2ccf7e5b29ab718c1dfcb10b3adf312628d8cd4fdba353b7670573add0

See more details on using hashes here.

File details

Details for the file payperbyte_sdk-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: payperbyte_sdk-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 34.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for payperbyte_sdk-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7014b5ff08b2dd21d4126c64a192012d5c9c45075b01d807cd0a453bd30f4bcc
MD5 fb44b5e6b21771178b06d20d89359731
BLAKE2b-256 c7c530c297a900c4b5b2b1180ea3af5507479238cbeabf736130a3753adc1a43

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.1

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page