
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
@payperbyte/sdk
Advanced tools
PayPerByte TypeScript SDK for the BYTE Library — cryptographically attested, provenance-verifiable data for AI agents (proves who signed the exact bytes, not data correctness). No token; direct-allowance USDC settlement on Arbitrum.
TypeScript SDK for PayPerByte (the BYTE Library) — the cryptographically attested, provenance-verifiable data layer for AI agents. Discover first-party feeds, subscribe, stream payloads, and verify every payload against its on-chain EIP-712 attestation (provenance + tamper-evidence — who signed these exact bytes — not a correctness guarantee). No token; USDC settlement on Arbitrum.
npm install @payperbyte/sdk
import {
ByteClient,
Subscriber,
Mercat,
verifyFromEvent,
ARBITRUM_SEPOLIA,
} from "@payperbyte/sdk";
// `network` is a NetworkConfig object (ARBITRUM_SEPOLIA / LOCAL_ANVIL),
// not a string. RPC URL + contract addresses come from that config.
const client = new ByteClient({ network: ARBITRUM_SEPOLIA });
// Discover publishers and their feeds via the indexer (Mercat).
const mercat = new Mercat(ARBITRUM_SEPOLIA.indexerUrl);
const publishers = await mercat.search({ topic: "eth-price" });
// Subscribe to a data feed — r2 DIRECT-ALLOWANCE model. There is NO escrow.
// subscribe(publisher, allowanceUsdc) does two on-chain things:
// 1. dataRegistry.subscribe(publisher) — the social-registry flag, and
// 2. usdc.approve(dataStream, cap) — the spending cap the publisher's
// streamData/streamBroadcast transferFrom-pulls each per-message fee from.
const subscriber = new Subscriber({
network: ARBITRUM_SEPOLIA,
privateKey: "0x...",
});
await subscriber.subscribe(publishers[0].address, 10.0); // $10 allowance cap
// Verify-before-act: recompute the hash AND recover the signer before trusting a
// single byte. verifyFromEvent is the FULL check for an on-chain attestation; the
// x402 gateway path uses verifyFromGatewayResponse (see Foreseal Kit below). The
// hash-only verifyPayload() is the lower-level leg — prefer the full check.
const verdict = await verifyFromEvent(message, receivedBytes, ARBITRUM_SEPOLIA);
if (!verdict.verified) throw new Error(verdict.reason); // do not act on unverified bytes
For one-off, pay-per-call access there is the keyless x402 GatewayClient. A
wallet signs the payment (gasless EIP-3009 transferWithAuthorization — the
facilitator broadcasts and pays gas). There is no API key: the wallet is the
credential. The @x402/core + @x402/evm packages are optional peer deps,
loaded only if you use the gateway.
import { privateKeyToAccount } from "viem/accounts";
import { createPublicClient, http } from "viem";
import { arbitrumSepolia } from "viem/chains";
import { GatewayClient } from "@payperbyte/sdk";
const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY as `0x${string}`);
const publicClient = createPublicClient({ chain: arbitrumSepolia, transport: http() });
// Defaults to https://x402.payperbyte.io; pass baseUrl for local dev (:3402).
const gw = new GatewayClient({ signer: account, publicClient });
// Discover the catalog (free) — each feed carries its priceAtomic.
const { feeds } = await gw.discover();
// Pay-per-call a GET feed: unpaid → 402 → wallet signs USDC → retry → data.
const { data, settlement, disclaimerCategory } = await gw.fetchFeed("defi-yields");
console.log(settlement?.transaction); // on-chain settlement tx hash
// POST oracle (address-reputation): a synchronous signed verdict — pass the query
// body; the paid 200 returns { answer, attestation } you verify before acting.
await gw.fetchFeed("address-reputation", {
body: { domain: "github.com", address: "0x1111111111111111111111111111111111111111" },
});
Two distinct USDC flows: the on-chain direct-allowance
approve(dataStream)at subscribe time (Subscriber) is independent of the x402 EIP-3009 sign at fetch time (GatewayClient). Pay-per-call via the gateway needs no prior subscription — the wallet signature is the only credential.
The Foreseal Kit is the SDK's headline primitive: sign, verify, and read a publisher's quality score — so any agent can produce and fully verify a PayPerByte PayloadAttestation without us in the request path.
The legacy verifyPayload() checks only the hash (keccak256(bytes) == attestedHash).
The Foreseal Kit adds the missing signer leg: it recovers the EIP-712 attestation
signer and confirms it is the publisher the catalog says it is. A single Verdict
composes both legs.
import {
signAttestation,
verifyFromGatewayResponse,
verifyFromEvent,
verifyAttestation,
getPQS,
ARBITRUM_SEPOLIA,
} from "@payperbyte/sdk";
// 1) verifyFromGatewayResponse — the headline call for the x402 gateway path (what
// most agents use). It is the FULL decision: recompute keccak256(body) AND recover
// the EIP-712 signer under the net-pinned consensus domain, refuse a forked wire
// domain, and assert the signer is the gateway attester you pinned out-of-band
// (REQUIRED — a self-asserted header can't prove provenance; omitting it fails closed).
const body = await res.text(); // the EXACT paid-200 bytes
const header = res.headers.get("X-BYTE-Attestation"); // the raw receipt header
const verdict = await verifyFromGatewayResponse(body, header, ARBITRUM_SEPOLIA, knownGatewayAttester);
// Verdict: { verified, hashMatch, signerMatch, recovered, expired, reason }
if (!verdict.verified) refuse(verdict.reason); // do NOT act on unverified bytes
// On-chain anchor (subscriber/stream path), same EIP-712 domain:
await verifyFromEvent(event, receivedBytes, ARBITRUM_SEPOLIA);
// Lower-level: verifyAttestation takes the fields explicitly (the call the two
// wrappers above compose). verifyPayload() is the hash-only leg — prefer the above.
const v2 = await verifyAttestation({
payloadBytes: receivedBytes,
attestation: event.attestation,
expectedPublisher: publisherAddr,
payloadHash: event.payloadHash,
payloadLength: event.payloadLength,
deadline: event.attestationDeadline,
net: ARBITRUM_SEPOLIA,
});
// 2) sign — produce an attestation (any viem WalletClient/Account).
const sig = await signAttestation(
{ publisher: account.address, payloadHash, payloadLength, deadline },
account,
ARBITRUM_SEPOLIA,
);
// 3) getPQS — read the indexer delivery-quality composite (BPS 0-10000).
const pqs = await getPQS(publisherAddr, ARBITRUM_SEPOLIA.indexerUrl);
// { composite, dispute, retention, freshness, revenueQuality, asOf }
// composite === null → publisher not yet scored.
Verdict rules (these are the contract):
| Case | hashMatch | signerMatch | verified |
|---|---|---|---|
| Known-good | true | true | true |
| Tampered bytes | false | — | false |
| Wrong/forged signer | true | false | false |
| Empty/missing attestation | (computed) | null | false — fail-closed |
"0x") or null
attestation yields signerMatch=null and verified=false. We never "pass on the
hash alone" — provenance is unproven without the publisher's signature.now+300s deadline elapses on
every aged feed. verifyAttestation sets expired=true but does not fail
verified on the immutable on-chain anchor — staleness belongs to a freshness
axis, not the provenance verdict. The caller decides policy.getPQS is off-chain, advisory, and may
be absent.BYTE Library EIP-712 domain literal is consensus-critical and identical
across the on-chain contract, gateway, MCP, and SDK. It is never renamed.approve(dataStream), no escrow)keccak256(bytes) against the on-chain hash before acting on the data| Network | Chain ID | Status |
|---|---|---|
| Arbitrum Sepolia | 421614 | Live (testnet) |
| Arbitrum One | 42161 | Planned (mainnet, audit-gated) |
PayPerByte runs on the BYTE Library — a lean 3-contract core. No token; all settlement is in USDC via a direct-allowance model (the subscriber approves DataStream; the publisher transferFrom-pulls each per-message fee — there is no escrow contract). Each payload carries an EIP-712 PayloadAttestation so subscribers can confirm exactly what they received and from whom.
| Contract | Role |
|---|---|
| DataRegistryLib | Publisher registration, feed/subscriber discovery |
| DataStreamLib | Per-call / per-byte payload delivery + settlement |
| SchemaRegistry | Feed schema + methodology references |
Contract addresses are resolved per-network by the SDK (ARBITRUM_SEPOLIA, LOCAL_ANVIL).
ByteClient — low-level client holding the viem clients and contract instances (used by Publisher/Subscriber)Publisher — register a feed, publish data, sign EIP-712 PayloadAttestationsSubscriber — subscribe, receive payloads, stream eventsverifyPayload / verifyEventPayload / fetchAndVerify — subscriber-side hash-only payload verification against on-chain attestationssignAttestation, verifyAttestation / verify (hash and signer recovery), verifyFromEvent, verifyFromGatewayResponse, getPQSMercat — feed search and discovery (connects to the indexer API)GatewayClient — keyless x402 pay-per-call client (a wallet signs, not an API key); discover, discoverResources, fetchFeedMIT
FAQs
PayPerByte TypeScript SDK — cryptographically attested, provenance-verifiable data for AI agents: proves which publisher signed the exact bytes (authenticity + tamper-evidence, not data correctness). Pay-per-call via x402 in USDC on Base mainnet; every pa
The npm package @payperbyte/sdk receives a total of 38 weekly downloads. As such, @payperbyte/sdk popularity was classified as not popular.
We found that @payperbyte/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.