Labs Protocol v0.1

Status: Phase 0 foundation Network: Base Sepolia (chain ID 84532) Asset: USDC / tUSDC (6 decimals), amounts in atomic units as strings

Design rule

A wallet signature proves authorization (control of a key). It does not prove settlement (that tUSDC moved on-chain).

PayPort Labs therefore supports two explicit modes:

PAYMENT_MODEMeaning
mockSimulated settlement. Signature verified; payment_verified=false.
base_sepoliaReal settlement. Signature + on-chain Transfer verification; payment_verified=true.

Never teach students that EIP-191 alone equals payment.

Architecture

PayPort Labs Platform (:8121)
├── Web dashboard / SIWE auth
├── Service directory
├── Transaction index
└── Leaderboard shell

Independent Merchant Node (e.g. :8122)
├── /.well-known/agent.json
├── /health
├── /v1/paid-resource
└── challenge issue + proof verify

Buyer Agent
├── discovers merchant
├── receives 402
├── settles or signs (per mode)
└── retries with X-Payment-Proof

HTTP 402 challenge body

{
  "detail": {
    "x402": {
      "protocol_version": "0.1",
      "challenge_id": "ch_…",
      "service_id": "sentiment-v1",
      "amount": "100000",
      "decimals": 6,
      "asset": "USDC",
      "network": "base-sepolia",
      "chain_id": 84532,
      "recipient": "0x…",
      "expires_at": "2026-08-02T15:30:00Z",
      "payment_modes": ["mock", "onchain"],
      "nonce": "…",
      "token_contract": "0x…"
    }
  }
}

100000 with decimals: 6 = 0.10 USDC. Do not use floating-point prices in the protocol.

X-Payment-Proof

Header value is a base64url-encoded JSON object (raw JSON also accepted):

{
  "protocol_version": "0.1",
  "challenge_id": "ch_…",
  "payer": "0xBuyer",
  "recipient": "0xMerchant",
  "amount": "100000",
  "asset": "USDC",
  "token_contract": "0x…",
  "chain_id": 84532,
  "service_id": "sentiment-v1",
  "nonce": "…",
  "expires_at": "2026-08-02T15:30:00Z",
  "tx_hash": null,
  "signature": "0x…"
}
  • mock: tx_hash must be absent/null. Settlement result: authorization_verified=true, payment_verified=false, settlement_mode=mock.
  • base_sepolia: tx_hash required. Merchant verifies Transfer(payer→recipient, amount) on the USDC contract, then marks payment_verified=true.

Authorization message (EIP-191)

Canonical newline-joined fields signed with personal_sign / encode_defunct:

protocol_version:0.1
challenge_id:ch_…
payer:0x…
recipient:0x…
amount:100000
asset:USDC
chain_id:84532
service_id:sentiment-v1
nonce:…
expires_at:2026-08-02T15:30:00Z

Challenge lifecycle

issued → settled → consumed

Persisted fields: challenge_id, nonce, service, optional expected payer, recipient, amount, asset, chain, expiry, status, consumed tx hash or mock proof id.

Replay rules:

  • Consumed challenge → PAYMENT_PROOF_ALREADY_USED
  • Reused tx_hash → TX_HASH_ALREADY_USED

Agent manifest

GET /.well-known/agent.json on each merchant node (not the Labs platform). Platform directory is GET /.well-known/labs.json.

Amounts in the manifest use base_price_atomic / endpoint amount strings (atomic units).

Error object

{
  "detail": {
    "code": "PAYMENT_PROOF_ALREADY_USED",
    "message": "This payment proof has already been consumed.",
    "challenge_id": "ch_…"
  }
}

Out of scope for v0.1

Dynamic pricing, reputation, negotiation, arcade/games, custodial keys, mainnet / PayPort Direct.