Canonical Format
The v1 pipe-delimited canonical payload specification — the string that gets signed.
Format
canonical string
v1|PAIR|PRICE|CURRENCY|DECIMALS|TIMESTAMP|NONCE|SOURCES|METHOD
Field Definitions
| Pos | Field | Type | Example | Description |
|---|---|---|---|---|
0 | Version | string | v1 | Format version. Always "v1" currently. |
1 | Pair | string | BTCUSD | Trading pair without slash. |
2 | Price | string | 84231.50 | Aggregated price as decimal string. |
3 | Currency | string | USD | Quote currency (USD or EUR). |
4 | Decimals | string | 2 | Decimal places in the price. |
5 | Timestamp | string | 2026-02-28T07:51:00Z | ISO 8601 UTC timestamp. |
6 | Nonce | string | 890123 | Server-generated nonce. Cannot be reproduced. |
7 | Sources | string | binance,bitstamp,... | Comma-separated, alphabetically sorted sources. |
8 | Method | string | median | Aggregation method: median or vwap. |
Real Example
BTC/USD canonical
v1|BTCUSD|67125.10|USD|2|2026-03-03T14:07:07Z|890123|binance,binance_us,bitfinex,bitstamp,coinbase,gateio,gemini,kraken,okx|median
Signing Process
pseudocode
canonical_bytes = canonical_string.encode("utf-8") digest = SHA256(canonical_bytes) signature = sign(digest, private_key) output = base64_encode(signature)
Pre-hashed signing
Both protocols sign the SHA-256 digest, not the raw bytes. For Ed25519 (x402), the actual operation is Ed25519(SHA-256(canonical)). See Signature Verification for details.
Parsing
python
fields = canonical.split("|") price = fields[2] # "67125.10" sources = fields[7].split(",") # ["binance", ...] timestamp = fields[5] # "2026-03-03T14:07:07Z"
Source ordering
Sources are always sorted alphabetically for deterministic canonical strings — the same set of sources always produces the same string regardless of fetch order.