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_MODE | Meaning |
|---|---|
mock | Simulated settlement. Signature verified; payment_verified=false. |
base_sepolia | Real 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_hashmust be absent/null. Settlement result:authorization_verified=true,payment_verified=false,settlement_mode=mock. - base_sepolia:
tx_hashrequired. Merchant verifies Transfer(payer→recipient, amount) on the USDC contract, then markspayment_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.