REAX.docs Pre-release · not on testnet
MenuProtocol reference

Reference

Protocol reference

Constants, the decision request schema, Jev-compatible question and answer types, probability transport, signed envelopes, miner responses, receipts, admission snapshots and error classes. Field names are taken from the reference code and spec revision 0.6.

Pre-release wire format

These formats will change before any network launch. Where the reference code and spec 0.6 differ, this page shows what the code does today and notes the spec target. Values marked (provisional) live in signed policy and are not protocol facts.

Constants

ConstantValueNotes
Canonical formRFC 8785 (JCS)Signed field names ASCII only. Already used by the reference code; required from G1
SignatureEd25519 (RFC 8032)Public keys validated as curve points on load. Serving keys are separate from Bittensor wallet keys
HashSHA-256, lowercase hex
Clock skew allowance2 000 ms (provisional)
Request lifetime≤ 60 000 msMAX_REQUEST_LIFETIME_MS in code
Request bytes≤ 256 KiB excluding images (provisional); state ≤ 64 KiB; each question text or criteria string ≤ 8 KiBSpec target. Code today: miner wire body ≤ 1 MiB while images are disabled
Images≤ 4 per request; each ≤ 6 MiB decoded; PNG, JPEG or WebP with matching magic bytes; ≤ 4 096 px per side and ≤ 16 777 216 pxDecoded only in an isolated worker. Disabled at the network miner today. Code today: ≤ 4 000 000 px
Sequence numbersIntegers in [1, 253 − 1]
Ledger epochepoch_tempos = 4 tempos (provisional)Tempo read only from the chain-profile readback
Fidelity windowW = 6 ledger epochsStrictly non-overlapping; one statistical look per window
Probability transportJSON numbers read as IEEE-754 binary64Sum within 1e-6 of 1 is renormalized; anything else is rejected
Questions per request≤ 32MAX_QUESTIONS in code
Options or levels per question2 – 64MAX_OPTIONS in code

Request schema

A decision request is a JSON object validated by DecisionRequest.from_payload. Unknown fields are rejected, not ignored. All values must be finite JSON that RFC 8785 can canonicalize.

FieldTypeRule
protocol_versionstringMust be "1"
request_idstring^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$
noncestring32–128 URL-safe characters [A-Za-z0-9_-]
tierstringgdpr_eu or global_permissionless
modelstringPublic catalog alias, ^[a-z0-9][a-z0-9._-]{0,63}$
stateany JSONThe context the questions are about
questionsobject1–32 questions keyed by stable IDs (same pattern as request_id)
imagesarray, optional≤ 4 data URLs data:image/(png|jpeg|webp);base64,…, each non-empty and ≤ 6 MiB decoded
deadline_unix_msintegerIn the future and at most 60 000 ms (plus the peer skew allowance of up to 2 000 ms) ahead

An illustrative request with one question of each type:

{
  "protocol_version": "1",
  "request_id": "req-0001",
  "nonce": "b3Vy-ZXhhbXBsZS1ub25jZS0zMi1jaGFycy1taW4",
  "tier": "global_permissionless",
  "model": "example-alias",
  "state": { "ticket": "Order 1042 arrived damaged. The customer wants their money back." },
  "questions": {
    "wants_refund": { "type": "noul", "instructions": "Is the customer asking for a refund?" },
    "queue": {
      "type": "choice",
      "instructions": "Which queue should handle this ticket?",
      "criteria": { "billing": "Payments and refunds", "shipping": "Delivery problems", "other": "Anything else" }
    },
    "urgency": {
      "type": "score",
      "instructions": "How urgent is this ticket?",
      "criteria": ["low", "medium", "high"]
    }
  },
  "deadline_unix_ms": 1790000000000
}

The model alias is a placeholder; no public catalog is published yet. A real deadline_unix_ms must be within 60 seconds of the current time.

Question types

REAX keeps the Jev-compatible typed-decision shape. Each question object may contain only type, instructions (any JSON) and criteria.

TypeCandidate setcriteria
noultrue / falseOptional. If present, an object with exactly the keys true and false
choiceOne of N optionsRequired object with 2–64 entries keyed by option ID
scoreOne of N ordered levelsRequired array of 2–64 levels, lowest first

Answers

A response must contain exactly one answer per question ID. Each answer must have exactly the fields below; any extra field (for example an explanation) fails validation.

TypeFieldsRules
noultype, noulnoul is a probability in [0, 1]
choicetype, choice, confidence, probabilitiesprobabilities has exactly the declared option IDs; choice is the first maximum-probability option; confidence equals its probability
scoretype, score, confidence, probabilities, legendprobabilities keyed "0"…"N-1"; score equals the expected level Σ i·pi; confidence equals the largest probability; legend maps each index to its original criteria level

Answers for the request above:

{
  "wants_refund": { "type": "noul", "noul": 0.94 },
  "queue": {
    "type": "choice",
    "choice": "billing",
    "confidence": 0.81,
    "probabilities": { "billing": 0.81, "shipping": 0.15, "other": 0.04 }
  },
  "urgency": {
    "type": "score",
    "score": 1.1,
    "confidence": 0.5,
    "probabilities": { "0": 0.2, "1": 0.5, "2": 0.3 },
    "legend": { "0": "low", "1": "medium", "2": "high" }
  }
}

Probability transport

Envelopes

Signed request envelope (code)

Both the gateway ingress and the miner accept a reax.request.v2 envelope. The signature is Ed25519 over the RFC 8785 form of the envelope without its signature field, hex-encoded (128 characters). It must have exactly these fields:

{
  "schema": "reax.request.v2",
  "audience": "<receiver: gateway audience or miner hotkey>",
  "caller": "<caller id>",
  "request": { "…": "decision request, as above" },
  "signature": "<128 hex chars>"
}

The caller must hold an unexpired grant for the request's tier. A grant fixes the caller's public key, tiers, expiry and exactly one data class; the data class lives only in the grant and never on the wire, so a customer request cannot be relabelled as synthetic.

Transport authorization header

Every HTTP call also carries Reax-Authorization: the unpadded base64url encoding of a signed reax.transport.v1 document, at most 2 048 bytes. It lets the receiver reject unknown callers before reading the body.

{
  "schema": "reax.transport.v1",
  "caller": "<caller id>",
  "audience": "<receiver>",
  "body_sha256": "<SHA-256 of the exact body bytes>",
  "expires_at_ms": 0,
  "signature": "<128 hex chars>"
}

Receivers accept an expiry no more than 62 s ahead; the reference clients emit at most 10 s and never beyond the request deadline.

Gateway dispatch

Before dispatch the gateway replaces the caller's request_id with a fresh d_-prefixed random ID and issues a fresh nonce, so customer-facing identifiers never reach a miner.

Spec 0.6 targets

Code vs spec

The code's data classes are synthetic and customer (spec: synthetic and real). The code forwards the full decision request, including its tier field, inside the miner envelope; spec 0.6 forwards only the allow-listed miner_payload and adds dispatch_id.

Miner response

Code today: reax.response.v1 with fields schema, miner, request_digest (SHA-256 of the canonical request envelope), nonce, result and signature. result contains request_id, model, answers, usage (input_tokens, output_tokens, decisions), latency_ms, tokenizer_version and model_revision. A full example is in the miner guide.

Spec 0.6: the signed body is reax.response.v2:

{
  "schema": "reax.response.v2",
  "miner_hotkey": "…",
  "serving_key_id": "…",
  "dispatch_id": "…",
  "request_digest": "<miner_payload_sha256>",
  "nonce": "…",
  "manifest_sha256": "…",
  "answers": { },
  "usage": { "input_tokens": 0, "output_tokens": 0, "decisions": 0 },
  "completed_at_ms": 0
}

The gateway must reject the response on any of: wrong signature or key; digest, dispatch ID or nonce mismatch; a manifest_sha256 that is not the admitted or registered manifest; decisions not equal to the number of questions; an answer field outside the per-type allow-list; a probability vector that fails transport rules; arrival after the deadline on the gateway's monotonic clock; or a revocation of the miner, operator, serving key, manifest, origin or subprocessor observed while the request was in flight. completed_at_ms is informational.

Receipts

Receipts are payload-free. They never contain the request, the answer, a customer identifier or a label.

Code today (gateway ledger)Spec 0.6 reax.receipt.v2
request_id (caller-scoped keyed ID), tier, miner_uid, model_revision, policy_digest, response_digest, measured_latency_ms, observed_at_ms, status, plus a ledger-keyed signatureRequest ID, tier, data class, miner hotkey and UID, manifest, policy digest; request fingerprint, miner_payload_sha256, dispatch_id, response digest; usage, measured latency, outcome, delivery, billing-policy ID, canon; leaf_commitment on every receipt. Ed25519-signed with a key_id

A receipt may say authenticated only after every check passes. It never says verified: signatures and digests do not prove model execution or answer correctness. Answers exist only in gateway memory until written to the caller; spec 0.6 target: a retry of a completed request returns 409 completed_not_retained with the receipt ID and no answer. The code today returns 409 request_conflict.

Admission snapshot

GDPR-tier miners are admitted through a short-lived snapshot signed by the admission issuer. Serving processes hold only the public verification keys, and every verifier persists a monotonic sequence floor so an older snapshot can never be re-accepted.

LevelCode today (reax.admission.v2)Spec 0.6 (reax.admission.v3)
Documentschema, key_id, sequence, issued_at, expires_at, entries, signature; validity ≤ 24 hAdds network, genesis_hash, netuid, audiences, policy_epoch; validity ≤ 24 h (6 h recommended, provisional)
Entryhotkey, country_code (EU member state), models, model_revisions, serving_public_key, and SHA-256 evidence references company_ref_sha256, dpa_sha256, kyb_sha256, location_attestation_sha256, identity_attestation_sha256hotkey, coldkey, operator_id, establishment_country, processing_countries, subprocessors (each with an authorization digest), endpoint_origin, tls_spki_sha256, serving_public_key, manifests, models, evidence

Snapshots contain digests of independently checked evidence, never identity documents. Digests bind records; they do not make the records true. Spec 0.6 adds a durable, restrict-only revocation feed (reax.revocation.v1) whose entries never expire, a checkpoint that makes an emptied store fail closed, and routing that matches the requested region against every processing and subprocessor country.

Error classes

Reference code exceptions

ExceptionRaised when
ProtocolErrorA request or answer violates the versioned schema (fields, formats, limits, probabilities, deadline)
AuthenticationErrorEnvelope, signature, audience, grant, tier or transport authorization fails, or a request or nonce was already claimed
RouteDeniedPolicy leaves no eligible miner with capacity (for example a disabled route or a missing admission snapshot)
IntegrityFailureA miner result does not match its approved identity, the question set, the answer rules or the deadline
EngineProtocolErrorThe local engine or a remote miner cannot satisfy the contract
AdmissionErrorA signed admission snapshot is invalid, stale or rolled back
ChainGuardErrorA chain identity, runtime, freshness or commit-reveal guard fails

HTTP status codes

StatusBody errorMinerGateway
400invalid_requestyesyes
403unauthorized_or_replayedyesyes
404not_foundyesyes
409request_conflict–yes
429capacityyesyes
502inference_failedyesyes
503route_unavailable–yes
504deadline_exceededyesyes

Attempt outcomes

Validators record every scheduled attempt with one typed outcome. The first five are scored attempts (success counts for the miner, the other four against it); the rest are excluded because the miner is not at fault or the attempt is not a scored dispatch.

OutcomeAvailability
successSuccess
timeout, unavailable, invalid, wrong_identityMiner-attributable failure
queue_expired_before_dispatch, capacity_burst_unscored, validator_fault, gateway_egress_fault, chain_rpc_fault, revoked_in_flightExcluded

Named conditions in spec 0.6

revoked_in_flight
A matching revocation was observed between dispatch and delivery: answer withheld, retryable 503, charge voided, not scored.
revocation_stale
The revocation document is older than its freshness bound; GDPR dispatch fails closed.
payload_binding_mismatch
Dispatch and reference payload digests differ; observation discarded with no miner effect.
completed_not_retained
409 for a retry of a completed request; the answer is not stored anywhere (spec 0.6 target; code today returns request_conflict).
chain_mismatch
Live chain state differs from the signed chain profile; no transaction.
chain_constraint
The weight vector would violate a chain constraint; the validator abstains.
reveal_missing / reveal_mismatch
Post-reveal readback failed or differs by more than ±1 u16.