Canonical Format

The v1 pipe-delimited canonical payload specification — the string that gets signed.

Envelope Format

Every attestation follows a two-layer structure: a fixed envelope wrapping type-specific payload fields. Signing and verification operate on the complete canonical string.

envelope structure
VERSION | TYPE | <payload fields...> | TIMESTAMP | NONCE

Envelope Fields

FieldPositionTypeExampleDescription
VERSION0stringv1Format version.
TYPE1stringPRICE, ECON, COMMODITIES, VOLATILITY, SENTIMENT, STRESSAttestation type — determines payload structure.
TIMESTAMPN-1integer1741514400Unix timestamp (seconds). Always second-to-last.
NONCENinteger4829106-digit random nonce. Always last field.

PRICE Type

PRICE format
v1|PRICE|PAIR|PRICE_VALUE|CURRENCY|DECIMALS|SOURCES|METHOD|TIMESTAMP|NONCE
BTC/USD example
v1|PRICE|BTCUSD|84231.50|USD|2|binance,binance_us,bitfinex,bitstamp,coinbase,gateio,gemini,kraken,okx|median|1741514400|482910
EUR/USD example
v1|PRICE|EURUSD|1.15|USD|5|bankofcanada,bitstamp,cnb,ecb,ecbdirect,kraken,norgesbank|median|1741514400|719304

ECON Type

ECON format
v1|ECON|REGION|INDICATOR|VALUE|UNIT|PERIOD|VINTAGEDATE|SOURCEAGENCY|SERIESID|SOURCEMODEL|TIMESTAMP|NONCE
US CPI example
v1|ECON|US|CPI|326.785|index198284100|2026-02|2026-03-14|BLS|CUUR0000SA0|directapi|1741514400|830114
WTI crude example
v1|COMMODITIES|WTI|94.65|usdperbarrel|2026-03-09|2026-03-15|EIA|DCOILWTICO|directapi|1741514400|402341

VOLATILITY Type (MSVI)

VOLATILITY format
v1|VOLATILITY|PAIR|MSVI|VALUE|INDEX|RV:{rv}:{w},IV:{iv}:{w},TS:{ts}:{w},FR:{fr}:{w},PCR:{pcr}:{w}|REGIME:{regime}|CONFIDENCE:{c}|METHOD:v{n}|{TIMESTAMP}|{NONCE}
BTC/USD example
v1|VOLATILITY|BTCUSD|MSVI|49.98|INDEX|RV:42.40:0.3,IV:44.01:0.25,TS:1.03:0.15,FR:22.00:0.2,PCR:0.92:0.1|REGIME:MODERATE|CONFIDENCE:1.0000|METHOD:v1|1744416000|291847

The components field includes all five weights (RV, IV, TS, FR, PCR) allowing independent reconstruction and verification of the index value.

SENTIMENT Type (MSXI)

SENTIMENT format
v1|SENTIMENT|PAIR|MSXI|VALUE|INDEX|FR:{fr}:{w},SKEW:{skew}:{w},PCR:{pcr}:{w},TS:{ts}:{w},BASIS:{basis}:{w}|REGIME:{regime}|CONFIDENCE:{c}|METHOD:v{n}|{TIMESTAMP}|{NONCE}
BTC/USD example
v1|SENTIMENT|BTCUSD|MSXI|-9.88|INDEX|FR:-0.00:0.3,SKEW:-4.12:0.25,PCR:0.863:0.2,TS:0.923:0.15,BASIS:0.049:0.1|REGIME:NEUTRAL|CONFIDENCE:1.0000|METHOD:v1|1744416000|382910

Positive values indicate bullish positioning, negative values bearish. The components field includes all five weights (FR, SKEW, PCR, TS, BASIS) allowing independent reconstruction.

STRESS Type (MSSI)

STRESS format
v1|STRESS|MARKET|MSSI|VALUE|INDEX|VOL:{vol}:{w},STBL:{stbl}:{w},FR:{fr}:{w}|REGIME:{regime}|CONFIDENCE:{c}|METHOD:v{n}|{TIMESTAMP}|{NONCE}
Market example
v1|STRESS|MARKET|MSSI|64.32|INDEX|VOL:61.81:0.35,STBL:0.00:0.3,FR:38.57:0.35|REGIME:HIGH|CONFIDENCE:1.0000|METHOD:v1|1744416000|571923

Market-wide single number — not per-pair. The components field includes all three weights (VOL, STBL, FR) allowing independent reconstruction and stress source identification.

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 secp256k1 ECDSA (L402), ECDSA always operates on a hash. For Ed25519 (x402), the actual operation is Ed25519(SHA-256(canonical)) — your verification code must hash first. See Signature Verification for code examples.

Parsing

python
fields    = canonical.split("|")
version   = fields[0]    # "v1"
type_id   = fields[1]    # "PRICE" or "ECON"
payload   = fields[2:-2] # type-specific fields
timestamp = fields[-2]   # Unix integer
nonce     = fields[-1]   # 6-digit nonce

# For PRICE type:
if type_id == "PRICE":
    pair    = fields[2]  # "BTCUSD"
    price   = fields[3]  # "84231.50"
    sources = fields[6].split(",")  # ["binance", ...]

# For index types (VOLATILITY, SENTIMENT, STRESS):
elif type_id in ("VOLATILITY", "SENTIMENT", "STRESS"):
    pair       = fields[2]  # "BTCUSD" or "MARKET"
    index_name = fields[3]  # "MSVI", "MSXI", or "MSSI"
    value      = fields[4]  # index value
    components = fields[6]  # "FR:-0.00:0.3,SKEW:-4.12:0.25,..."
    regime     = fields[7].split(":")[1]  # "NEUTRAL"
Always use the canonical field directly

Never reconstruct the canonical string from other response fields. The nonce is server-generated and cannot be reproduced. Always verify against the canonical field returned in the response.