Moxie API Spec

Moxie API, RPC, and settlement reference.

The full reference surface for teams wiring production market infrastructure: clearing primitives, auth profiles, agent envelopes, JSON-RPC methods, settlement receipts, realtime streams, SDK install paths, pagination, errors, and amount utilities.

Clearing Model

Clearing, settlement, and market primitives

This page carries the detailed protocol material behind the SDK calls: settlement jobs, compliance preflight, portfolio margin, parimutuel and continuous clearing, receipt proofs, release/recovery, and certified hot-market deltas. The terminal runtime primitive is AdmissibleObligationTransition; ClaimGraph and ClaimCompiler are the target source-language layer for contract-shaped products.

1. Event-atomic settlement

A settlement job resolves the oracle event, pays winners, mints assets, burns tickets, and nets cross-position margin under one terminal receipt. Small jobs fit in one block; large cohorts chunk in deterministic order and expose no final participant state until the settlement_batch_root is finalized. NativeTx::SettlementBatch now has consensus type coverage and an executor path that validates cheap invariants, stages non-terminal chunks under settlement_batch_staging, records payout metadata, and applies terminal chunk effects under one root. NativeTx::PayoutReturned closes the bank-return leg: the authorized return debits the recorded recipient USDC, credits custody, records the return code, and emits TxReceiptEvent::PayoutReturned committed through eventsRoot. Two RPC methods round-trip batch admission: moxie_estimateSettlementBatch returns a deterministic manifest_root, gas estimate, and validation envelope, while moxie_submitSettlementBatch dispatches the signed write under the same security envelope as moxie_submitSigned. Successful terminal receipts surface settlementBatchRoot and events[] on RpcReceipt; inclusion proofs mirror settlementBatchRoot and eventsRoot on RpcMerkleReceipt.digestInput. See docs/architecture/SETTLEMENT_JOB.md for the moat #1 spec.

brand token + AMM swap
typescript
import { Client } from "@moxie/sdk";

const moxie = new Client();

// Brand list + token price
const brands = await moxie.getBrands();
const fightToken = brands[0]?.token_id ?? "0x<64-hex-token>";
const price = await moxie.getTokenPrice(fightToken);

// AMM swap — constant-product pool
const tx = await moxie.ammSwap({
  key: "0x<64-hex>",
  pool_id: "0x<64-hex-pool>",
  token_in: "USDC",
  token_out: fightToken,
  amount_in: "1000000000000000000000",
  min_amount_out: "950000000000000000000",
});

2. Prediction and parimutuel markets

Binary, multi-outcome, and parimutuel-style markets resolve before trades execute in the settlement block. A sports card, HKJC-style racing pool, bracket market, or live micro-bet can pay many winners from one resolved event. Prediction signals may influence related spot or AMM markets; AMM state never feeds back into the prediction payoff.

mint, trade, settle
typescript
const eventId = "0x<64-hex-event>";
const mint = await moxie.predictionMint({
  key: "0x<64-hex>",
  prediction_id: "0x<64-hex-prediction>",
  event_id: eventId,
  outcome_index: 0,      // McGregor
  amount: "500000000000000000000",
});

const odds = await moxie.getPredictionOdds(eventId);
console.log(odds);
// { outcomes: [...], probabilities: [...] }

// Settled in Phase 1 at resolution block — atomic
// with spot repricing through the PW-AMM coupling.

3. AMM/CLOB hybrid orderbook

Markets progress through five stages: BondingCurveEquilibriumAmmHybridAmmClobFullClobCrossListed. The orderbook merges synthetic AMM levels with resting CLOB orders. Spot orders, conditional orders, and contingent orders share a unified clearinghouse; cross-margined positions offset correlated exposure.

spot order + orderbook
typescript
const marketId = "0x<64-hex-market>";
const book = await moxie.getOrderBook(marketId);
console.log(book);
// { bids: [...], asks: [...], stage: "HybridAmmClob" }

const order = await moxie.spotOrder({
  key: "0x<64-hex>",
  market_id: marketId,
  is_buy: true,
  quantity: "1000000000000000000000",
  price: "2450000000000000000",
});

4. Continuous markets with LP fee accrual

Use a continuous market when the outcome is a range rather than a fixed list: item resale price, auction clearing price, implied probability, finishing time, weather, vote share, or any bounded numeric result. Under the hood this is Continuous-CPCAM over [omega_lo, omega_hi], discretised on a grid_size_code ∈ {N8, N16, N32, N64, N128, N256}, paired with a convex entropy generator. LPs provide shape-weighted range liquidity; swap_fee_bps of every Buy accrues back to LP positions prorated by liquidity_budget.

LP provision + withdraw
typescript
import { Client, ShapeCode } from "@moxie/sdk";

const moxie = new Client();

const provide = await moxie.provideContinuousLiquidity({
  key: "0x<64-hex>",
  position_id: "0x<64-hex>",
  market_id: "0x<64-hex>",
  omega_lo: "100000000000000000",
  omega_hi: "500000000000000000",
  shape_code: ShapeCode.Gaussian,
  shape_param_a: "300000000000000000",
  shape_param_b: "50000000000000000",
  liquidity_budget: "100000000000000000000",
});

// Observe: pending clearings + LP positions by market
const pending = await moxie.getPendingClearings({});
const lps = await moxie.getContinuousLpPositionsByMarket({
  market_id: "0x<64-hex>",
});

// Withdraw principal + accrued fees
const withdraw = await moxie.withdrawContinuousLiquidity({
  key: "0x<64-hex>",
  position_id: "0x<64-hex>",
});
Authentication

Four auth profiles — the same RPC surface

Every Moxie call resolves to one of four auth profiles. All four share the same underlying RPC surface: an AI agent holding a scoped agent credential is indistinguishable from a human developer backend at the RPC layer.

1. Developer backend (server-to-server)

Credential: mxk_sk_<env>_<kid>_<random> (secret, backend-only), optional mxk_pk_* publishable key (origin-pinned via Referer / Origin allowlist, scope-locked to reads). Exchange into short-lived mxat_<blake3> bearers via OAuth 2.0 Client Credentials at the mounted gateway or ops route POST /oauth/token. Postgres + Redis token store is the production target.

client_credentials
python
token = await http.post(
    "/oauth/token",
    json={
        "grant_type": "client_credentials",
        "client_id": "mxk_sk_prod_acme_kid42",
        "private_key_jwt": sign_jwt("acme", priv),
        "scope": "markets:read personas:write",
    },
)
access_token = token["access_token"]

2. Wallet-native player (SIWE)

EIP-4361 Sign-In-With-Ethereum remains the player-session target surface, implemented by gateways rather than the node JSON-RPC module. Subject is the wallet address, not email. Wallet default: MPC with passkey for new players (self-hosted threshold under Moxie ops, no permanent third-party custody); ML-DSA-65 post-quantum seed provisioned alongside; hardware upgrade (Ledger EIP-1193) on by default.

siwe.nonce → siwe.verify
typescript
const nonceRes = await fetch("/v1/auth/siwe/nonce", {
  method: "POST",
  body: JSON.stringify({ address, domain: "moxie.inc" }),
});
const { nonce } = await nonceRes.json();
const msg = buildSiweMessage({
  address, nonce, chainId, /* ... */
});
const sig = await wallet.signMessage(msg);
const sessionRes = await fetch("/v1/auth/siwe/verify", {
  method: "POST",
  body: JSON.stringify({ message: msg, signature: sig }),
});
const session = await sessionRes.json();

3. Delegated session key (macaroon-attenuated)

On top of SIWE, the gateway can mint a secondary secp256k1 session key bound on-chain as a restricted signer; this is not a shipped @moxie/sdk namespace. Biscuit/macaroon caveats (max_spend, persona, device, ttl) ride as first-party predicates on the signed-envelope params. Depth cap 8; attenuate-only; TTL-bounded. ERC-4337 account abstraction lives here: player smart-accounts are SimpleAccount behind a developer-funded Paymaster with per-player budgets.

Gateway session key
typescript
const keyRes = await fetch("/v1/auth/session-keys", {
  method: "POST",
  headers: { Authorization: `Bearer ${session.token}` },
  body: JSON.stringify({
    scope: ["native:transfer", "moxie_submitSigned"],
    caveats: [
      { max_spend: "10000000000000000000" },
      { device: "ios-abc" },
    ],
    ttl_seconds: 3600,
  }),
});
const sessionKey = await keyRes.json();

4. Admin (HSM-backed, m-of-n)

Static X-Admin-Key is retired. Every admin* RPC is a signed envelope from an HSM-rotatable admin signer (YubiHSM or CloudHSM), countersigned by a second admin via m-of-n matching the mez-recovery kill-switch ceremony signer set. Admin sessions require staff login plus WebAuthn step-up plus HSM-backed signing with role-based approval. Regulators get read-only auditor sessions via a separate OAuth client class; validators get node certificates + validator-key attestation, not admin credentials.

signed admin envelope
json
{
  "method": "admin_emergencyHalt",
  "envelope": {
    "signer_hsm_id": "yubi-01",
    "cosigner_hsm_id": "yubi-02",
    "cryptographic_epoch": 3,
    "composite_signature": "ed25519 ‖ ml_dsa_65 ‖ slh_dsa",
    "ceremony_id": "cer_01HX..."
  }
}
AI Agents

AI agents call Moxie the same way developers do

An AI agent can attach an AgentInvocation envelope to state-mutating SDK calls that opt into agent context. Depth-bounded delegation (≤ 8) under HARNESS-I, biscuit/macaroon attenuate-only scopes, composite ed25519 + ML-DSA-65 + SLH-DSA signatures, F22 chain verifier, F21 hash-chained audit record closing the loop (directive → prompt → model → plan → Moxie call → outcome). The MCP tool surface ships as @moxie/sdk-mcp — every continuous-market tool has a matching MCP binding.

MCP tool surface — @moxie/sdk-mcp

The MCP surface maps onto Continuous-CPCAM create, quote, swap, provide liquidity, withdraw, resolve, prune, market reads, LP reads, LP lists by market/owner, pending clearings, and resolved-market lookup. Each tool validates input via Zod against the same schemas the TypeScript SDK exposes. Agents that depend on the tool surface inherit the conformance corpus checks.

install
terminal
$ npm install @moxie/sdk-mcp
AgentInvocation envelope
typescript
// Agent-enabled gateways attach this envelope before submission.
const agentContext = {
  invocation_id: crypto.randomUUID(),
  agent_id: "did:moxie:agent:treasury-autopilot@v4",
  principal_chain: [
    "alice",
    "planner@v11",
    "treasury-autopilot@v4",
  ],
  delegation: {
    delegation_id: "b6...1f",
    scope: [
      ["OpInstance", "moxie:swap:usdc:moxie:le50k"],
      ["RuntimeBound", "per_tx_usd", 25000],
    ],
    ttl_ms: 120000,
    depth: 3,                        // cap ≤ 8
    revocable: true,
  },
  cryptographic_epoch: 3,
  composite_signature: "ed25519 | ml_dsa_65 | slh_dsa",
};

Introduction

Moxie is a programmable exchange for contract markets. A contract market can be as simple as an in-game item resale market or as complex as a racing pool, parlay, royalty-linked asset, insurance payout, coupon, or cross-market portfolio. The developer surface is ordinary SDK + JSON-RPC: create the market, quote the trade, submit the order, read the receipt, and subscribe to updates.

Under the hood, Moxie owns price discovery, clearing, settlement, liquidity, receipts, release/recovery, and reliance export. Mass supplies the institutional admissibility plane. The terminal runtime primitive is AdmissibleObligationTransition; event-contingent settlement, brand/IP, securities, insurance, parimutuels, coupons, payouts, non-event trading, and agent actions are TemplatePack/AOT lanes over the same kernel. ClaimGraph and ClaimCompiler are the typed source-IR/lowering layer for contracts and claims; the lowered AOT remains consensus truth.

The API is JSON-RPC 2.0 over HTTPS plus staged REST surfaces. The registered moxie_* catalog includes moxie_getBrandExperiences, moxie_merchOrder, the PTJC moxie_racing* surface, the settlement-job pair moxie_estimateSettlementBatch + moxie_submitSettlementBatch, and the terminal-kernel surface moxie_getTerminalKernelState, moxie_getTerminalTemplatePacks, moxie_getTerminalRelianceInstruments, moxie_getTerminalHotMarketStatus, moxie_lowerClaimGraph, and moxie_buildTransaction { method: "terminalKernel" }. The @moxie/sdk TypeScript client exposes flat named methods, SDK-owned wire types, typed errors, and the webapp compatibility facade; moxie-sdk (Rust, Python) are the Tier 1 counterparts. The SDK can call the mounted compliance preflight route today; signed native writes can echo a preflight binding into moxie_submitSigned, and racing writes also require idempotency plus a chain-bound chain_binding.settlement_batch. PTJC production wagering remains gated by the Thai legal opinion and deployment smoke witness. REST parity gating currently covers OAuth, corridor, webhooks, audit-chain, regulator, portfolio, app-install, agent-invocations, and revenue REST surfaces.

Base URLs

Production JSON-RPC
https://api.moxie.xyz
Local JSON-RPC
http://localhost:8545
Staged REST
/api/v1 routes mount beside the JSON-RPC endpoint for REST-only surfaces such as compliance preflight.

Content Type

All requests and responses use application/json.

SDK Method Families

TypeScript Client
Flat named methods such as health(), getBrands(), getBrandExperiences(), getLeaderboardPage(), getPools(), merchOrder(), ammSwap(), spotOrder(), getPerpMarkets(), and getCalibration().
Continuous-CPCAM
createContinuousMarket(), getContinuousMarket(), quoteContinuous(), swapContinuous(), LP reads/writes, pending clearings, and resolved-market pruning.
State sync
moxie_getStateRoot(block_height_hex) exposes retained block state roots with source: "block" and falls back to the bounded state_root_history ring after full block payloads are pruned. Heights beyond both windows return the canonical -32004 envelope with requested_height, chain_oldest_height, chain_newest_height, and pruned_count.
Leaderboard
moxie_getLeaderboard is a current-node legacy offset surface accepting brand_id/brandId, window, metric, offset, and limit. Expanded entries include rank, address, points, score, tier, score_components (token, experience, prediction, cultural, community), display_name, avatar_url, brand_id, rank_delta, and country_code. Legacy page envelopes include items, has_more, offset, limit, and stats with participant counts, tier counts, scoring weights, as_of_block, prediction_count, window, metric, and optional brand_id.
Terminal kernel
client.terminal() / client.terminal exposes terminal roots, full AOT state, ProductLegalProfile + TemplatePack registries, recognized reliance instruments, certified hot-market replay status, deterministic moxie_lowerClaimGraph, unsigned terminalKernel transaction building, and preflight-bound moxie_submitSigned submission.
Tickets
getTickets(), ticketCreate(), ticketPurchase(), and ticketRedeem() are native SDK/RPC methods. Ticket-create payloads still carry metadataHash for the native transaction envelope; ticket read models do not persist or return that field. Reads return ticketId, eventId, brandId, creator, tier, price, totalSupply, sold, section and seat fields, event and venue labels, timing fields, cardLabel, ticketImage, venueImage, and compatibility venue_image.
Merchandise
getMerchandise(), merchOrder(), purchaseMerch(), and merchFulfill() are shipped SDK/RPC methods. moxie_merchOrder returns a typed receipt with order_id, item_id, brand_id, buyer, quantity, unit_points, total_points, payment_token, status, created_at_block, optional escrow_tx_hash, optional estimated_delivery, and fulfillment_status.
PTJC racing
The Tier 1 SDKs expose racing() / client.racing over 21 registered moxie_racing* JSON-RPC methods: race-day, race, pool, dividend, bet, jockey, leaderboard, settlement-receipt, and racing epoch-commitment reads; bettor preview/place; and strict-admin race-card, pool lifecycle, result, void, settlement, and treasury-ledger writes. Racing writes enforce compliance commitment, idempotency replay semantics, and chain_binding.settlement_batch lowering through the generic settlement/AOT receipt path; successful writes return PENDING_CHAIN_RECEIPT until the canonical receipt lands. Production wagering remains blocked until legal and deployment witnesses close.
Rust resources
client.brands() including experiences(...) and merch_order(...), markets(), events(), drops(), personas(), accounts(), positions(), swaps(), chain(), governance(), perps(), predictions(), vault(), calibration(), compliance(), racing(), terminal(), arb(), and raw().
Python resources
client.accounts, brands including get_brand_experiences(...) and merch_order(...), drops, ephemeral, governance, markets, personas, staking, trading, racing, terminal, raw, and rpc().
Raw parity escape hatches
TypeScript client.call<T>(), Rust client.call<T>()/client.raw(), and Python client.rpc() cover the full registered method catalog when a typed wrapper lags.
Initialize client
typescript
import { Client } from "@moxie/sdk";

const moxie = new Client({
  apiKey: "mxat_...",
  baseUrl: "https://api.moxie.xyz",
});
Base request
curl
$ curl https://api.moxie.xyz \
  -H "Authorization: Bearer mxat_..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"moxie_health","params":[]}'
Response shape
json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "status": "healthy",
    "synced": true,
    "block": 847293,
    "peers": 12,
    "highestBlock": 847293,
    "chainId": 1337
  }
}

Authentication

The API uses Bearer token authentication. Four credential classes are issued in distinct forms: secret developer keys are prefixed mxk_sk_<env>_<kid>_, publishable developer keys mxk_pk_<env>_<kid>_, OAuth-exchanged bearer tokens mxat_, SIWE player sessions mxs_player_<addr>_, and short-lived Mass-app-install tokens miat_ (TTL ≤ 900s). Exchange a secret key into a bearer via the mounted gateway or ops route POST /oauth/token; pass the bearer as Authorization: Bearer on every request.

The SDK accepts the token via the apiKey constructor option. For client-side signing, pass a signer with addressFromPrivateKey() and signTransactionHash(). For admin routes, submit signed envelopes from an HSM-rotatable admin signer; see the Authentication overview above for the four auth profiles.

Server-to-server
typescript
const moxie = new Client({
  apiKey: "mxat_...",
});
Client-side signer
typescript
import { Client } from "@moxie/sdk";

const moxie = new Client({
  signer: {
    addressFromPrivateKey: deriveAddress,
    signTransactionHash: signHash,
  },
});

Mutating Calls

Writes use explicit idempotency, validation, and confirmation discipline. callMutation()-backed methods generate an Idempotency-Key from the registered RPC method when the caller does not provide one; racing JSON-RPC writes enforce same-key/same-body replay and same-key/different-body mismatch semantics, while broader mutation replay enforcement remains route-specific. SDK validators reject malformed event windows, amounts above MAX_TRANSFER_AMOUNT / MAX_STAKE_AMOUNT / MAX_ORDER_SIZE, reserved addresses, and oversized serialized transactions before transport. Signer-backed native helpers map SDK aliases such as ammSwap, spotOrder, and createContinuousMarket to their moxie_* RPC names for idempotency, then build, sign, submit through moxie_submitSigned, and wait for receipt confirmation by default. Pass waitForReceipt: false only when the caller owns polling.

Compliance preflight is available on supported NativeMutationOptions surfaces and on direct signed submissions through the preflight binding object accepted by moxie_submitSigned. When Mass compliance write admission is enabled, enhanced mutating calls fail closed unless the binding matches sender, purpose, entity ids, as-of block, TTL, jurisdiction, and commitment. A blocked verdict raises MoxieComplianceBlockedError with the server verdict preserved in error metadata.

Write Headers

Idempotency-Key
Generated by the SDK for mutating helpers when omitted. Valid keys are 1..255 chars using ASCII alphanumerics plus -_.:; racing JSON-RPC writes and idempotent REST mutation routes enforce replay on the server.
X-Request-Id
Preserved on SDK errors when the node or gateway returns it.
Retry-After
Preserved on rate-limit errors when present. SDK retry sleep currently uses exponential backoff.
Preflight + receipt discipline
typescript
const gate = await moxie.preflightCompliance({
  entity_ids: [accountEntityId],
  purpose: "TerminalKernel",
  jurisdiction: "USA",
});

const txHash = await moxie.terminal().submitSigned(signedEnvelope, {
  idempotencyKey: "terminal-aot-2026-04-30-001",
  preflight: {
    commitment: gate.commitment,
    asof_block: gate.asof_block,
    ttl_ms: gate.ttl_ms,
    entity_ids: [accountEntityId],
    purpose: "TerminalKernel",
    jurisdiction: "USA",
  },
});

// sendRawTransaction has already waited for a successful receipt.
console.log(txHash);

Errors

The API returns standard JSON-RPC wire errors as { code, message, data? }. The TypeScript SDK maps those and HTTP failures into subclasses of MoxieSdkError: MoxieRateLimitError, MoxieTimeoutError, MoxieNetworkError, MoxieJsonRpcError, MoxieComplianceBlockedError, MoxieAuthError, and MoxieInvalidInputError. Each preserves available JSON-RPC code, HTTP status, backend error code, request ID, retry-after value, and retryability metadata.

Server errors (5xx), rate-limit responses, JSON-RPC -32005, timeouts, and retryable network failures are automatically retried with exponential backoff up to maxRetries (default 3). Rate limit responses may include Retry-After and X-RateLimit-Remaining headers when the node or gateway provides them.

HTTP Status Codes

400 Bad Request
Malformed JSON, missing required fields, invalid parameter values.
401 Unauthorized
Missing or invalid API key.
404 Not Found
Resource does not exist.
429 Rate Limited
Rate limit exceeded. The SDK preserves Retry-After when present and retries with exponential backoff.
500 Internal Server Error
Server error. Automatically retried by the SDK.
Error handling
typescript
import {
  MoxieJsonRpcError,
  MoxieRateLimitError,
  MoxieSdkError
} from "@moxie/sdk";

try {
  await moxie.call("moxie_unknown", []);
} catch (err) {
  if (err instanceof MoxieRateLimitError) {
    console.log(`Retry in ${err.retryAfter ?? 1}s`);
  } else if (err instanceof MoxieJsonRpcError) {
    console.log(err.code, err.requestId);
  } else if (err instanceof MoxieSdkError) {
    console.log(err.kind, err.status);
  }
}

Pagination

Canonical pagination follows the Moxie PLATONIC I-9 cursor-only contract: clients pass opaque cursors through unchanged, never decode them, and treat null / absent cursor as the first page. Current-node legacy JSON-RPC list handlers still accept limit and offset on explicitly documented surfaces and cap limit at 200.

Do not inspect or derive meaning from pagination tokens. Cursor surfaces advance with the backend-provided cursor. Current-node legacy offset surfaces advance by the number of returned items until the handler migrates to the cursor envelope.

Response Fields

items array
Array of resource objects.
cursor string | null
Opaque cursor supplied by cursor-contract surfaces. Pass through unchanged.
offset number
Current-node legacy offset for explicitly marked JSON-RPC list handlers only.
has_more boolean
Whether additional pages exist.
limit number | null
Effective page size after the backend cap.
Current-node legacy offset pagination
typescript
import { Client, RpcLeaderboardEntry } from "@moxie/sdk";

type LeaderboardPage = {
  items: RpcLeaderboardEntry[];
  has_more: boolean;
  offset: number;
  limit: number;
};

const client = new Client();
let offset = 0;
let hasMore = true;
do {
  const page = await client.call<LeaderboardPage>("moxie_getLeaderboard", [{
    brand_id: "0x<brand>",
    window: "weekly",
    metric: "points",
    limit: 20,
    offset,
  }]);
  page.items.forEach(row => console.log(row.rank, row.address, row.points));
  offset += page.items.length;
  hasMore = page.has_more;
} while (hasMore);

Amounts

All monetary values on the wire are raw 18-decimal strings. "1000000000000000000" equals 1.0 USDC (the primary settlement currency). Never use parseFloat() on raw amounts: they exceed JavaScript’s safe integer range.

The SDK exports wire-safe helpers directly from @moxie/sdk.

Utilities

parseFixedPointDecimal(value) string → string
Convert human-readable "1000.5" to wire format "1000500000000000000000".
formatFixedPointRaw(raw) string → string
Convert wire format to human-readable decimal string.
coerceFixedPointString(raw) string → string
Validate an existing raw wire value and return the canonical decimal integer string.
Amount conversion
typescript
import {
  coerceFixedPointString,
  formatFixedPointRaw,
  parseFixedPointDecimal
} from "@moxie/sdk";

parseFixedPointDecimal("100");
// "100000000000000000000"

formatFixedPointRaw("1000000000000000000");
// "1"

coerceFixedPointString("1500000000000000000000");
// "1500000000000000000000"

Brands

A Brand represents an IP-linked derivative on the clearing network: a sports league, entertainment property, or cultural franchise whose token price is coupled to real-world event outcomes. Each brand has a token, a market stage, a temperature regime (Cold/Warm/Hot regulatory graduation), and a revenue pool that accumulates fees from trading, licensing, drops, and auctions.

GET /api/v1/brands

Lists all brands. The current JSON-RPC handler is moxie_getBrands; the REST route returns the same RpcBrand[] wire objects without pagination metadata.

Scheduled brand experiences are exposed by moxie_getBrandExperiences with an optional brand ID filter. The Tier 1 SDK names are TypeScript getBrandExperiences(brandId?), Rust client.brands().experiences(Some(brand_id)), and Python client.brands.get_brand_experiences(brand_id). Each experience carries id, brand_id, title, subtitle, category, starts_at, location, points_cost, capacity fields, tier requirement, featured flag, and status.

Merchandise is exposed by moxie_getMerchandise, moxie_purchaseMerch, moxie_merchOrder, and moxie_merchFulfill. The typed order path is TypeScript merchOrder(params), Rust client.brands().merch_order(params), and Python client.brands.merch_order(...); it returns the RpcMerchOrderReceipt fields documented in the method-family summary.

REST Notes

regime string optional
Use client-side filtering today; gateway-level filters can be layered without changing the wire object.
sort string optional
Use client-side sorting today; stable sort fields are price, ticker, and reserve fields.
search string optional
Use moxie.search() for cross-resource search; /api/v1/brands itself is a list route.

Brand Object

brand_id string
32-byte brand identifier.
ticker string
Ticker symbol. e.g. FIGHT, CITY, PLAY
token_id string
32-byte token identifier backing the brand.
reserve_brand string
Brand reserve in raw 18-decimal wire format.
price string
Current price in USDC (18-decimal wire format).
List brands
typescript
const brands = await moxie.getBrands();
brands.forEach((brand) => {
  console.log(brand.ticker, brand.price);
});
Response 200
json
[
  {
    "brand_id": "0x<64-hex-brand>",
    "token_id": "0x<64-hex-token>",
    "ticker": "FIGHT",
    "name": "UFC",
    "price": "2470000000000000000",
    "reserve_brand": "1000000000000000000000",
    "reserve_moxie": "2470000000000000000000"
  }
]
Related economics primitives
typescript
const tokenId = brands[0]?.token_id;
if (tokenId) {
  const [price, volumes, stages] = await Promise.all([
    moxie.getTokenPrice(tokenId),
    moxie.getPoolVolume(),
    moxie.getMarketStages(),
  ]);
}

Markets

Markets represent trading venues for brand tokens. Each market progresses through five stages: BondingCurve, EquilibriumAmm, HybridAmmClob, FullClob, and CrossListed. The orderbook merges synthetic AMM levels with resting CLOB orders.

GET moxie.getMarkets()

Lists all markets through JSON-RPC. Filter client-side by brand, regime, volume, spread, or price.

GET /api/v1/markets/{marketId}/candles

Retrieves candle data for a market. Single-market summary reads use SDK/JSON-RPC helpers.

GET /api/v1/markets/{marketId}/orderbook

Returns L2 orderbook depth. Bids and asks include price, quantity, and order count at each level.

Market Object

stage string
Market lifecycle stage. Determines which trading primitives are active.
price string
Last trade price (18-decimal).
bid / ask string
Best bid and ask prices (18-decimal).
spread string
Bid-ask spread (18-decimal).
Get orderbook
typescript
const book = await moxie.getOrderBook(
  "0x<64-hex-market>"
);

book.bids.forEach(level => {
  console.log(level.price, level.quantity, level.order_count);
});
Response 200
json
{
  "market_id": "0x<64-hex-market>",
  "bids": [
    { "price": "2450000000000000000", "quantity": "500000000000000000000", "order_count": 3 },
    { "price": "2440000000000000000", "quantity": "1200000000000000000000", "order_count": 7 }
  ],
  "asks": [
    { "price": "2480000000000000000", "quantity": "300000000000000000000", "order_count": 2 }
  ],
  "bid_count": 10,
  "ask_count": 8
}

Swaps

AMM swaps execute against constant-product pools with Probability-Weighted AMM coupling. The pool price adjusts based on prediction market outcomes through a bounded geometric function.

GET /api/v1/pools

Lists all AMM pools with reserves, fees, and 24h volume.

GET /api/v1/swaps/quote/{token}

Returns the token-side quote fixture exposed by the REST node. For executable slippage protection, compute and pass min_amount_out to the SDK mutation.

POST /api/v1/swaps

Executes an AMM swap. SDK write helpers return a transaction hash and wait for a successful receipt by default; use waitForReceipt(txHash) only when polling manually.

Body Parameters

pool_id string required
Pool identifier.
token_in / token_out string required
USDC/MOXIE aliases or 32-byte token IDs for the swap direction.
amount_in string required
Input amount as a raw 18-decimal integer string. Use parseFixedPointDecimal() for human decimal conversion.
min_amount_out string required
Minimum output for slippage protection. Must be > 0.
Swap with slippage bound
typescript
import { parseFixedPointDecimal } from "@moxie/sdk";

const txHash = await moxie.ammSwap({
  key: "0x<64-hex>",
  pool_id: "0x<64-hex-pool>",
  token_in: "USDC",
  token_out: "0x<64-hex-token>",
  amount_in: parseFixedPointDecimal("1000.0"),
  min_amount_out: parseFixedPointDecimal("950.0"),
});

// ammSwap has already waited for a successful receipt.
console.log(txHash);

Continuous-CPCAM

Continuous-outcome AMM over an interval [omega_lo, omega_hi], discretised on a grid, paired with a convex entropy generator. Three creator choices are integer-coded on the wire: grid_size_code ∈ 0..=5 (N8, N16, N32, N64, N128, N256), generator_code ∈ 0..=4 (Quadratic, Entropy, Logarithmic, PowerMean2, ExponentialKernel), and an optional swap_fee_bps ∈ 0..=10000 (basis points of every Buy accruing to LP positions prorated by liquidity_budget). LPs provide range liquidity with a shape (shape_code ∈ 0..=2: PiecewiseConstant, Gaussian, Exponential); withdraw returns principal plus accrued fees. Quotes may defer when the integrator has not converged; a deferred quote returns pending_id and the caller polls getPendingClearings.

POST moxie_createContinuousMarket

Creates a continuous market. Body fields: key (64-hex transaction key), market_id (64-hex), omega_lo / omega_hi (18-decimal FixedPoint wire strings), grid_size_code, generator_code, initial_mu (array of FixedPoint; size matches the grid), and optional swap_fee_bps.

GET moxie_getContinuousMarket

Reads market state by market_id: generator, grid, current mu, total liquidity budget, fee accumulator.

POST moxie_quoteContinuous

Returns { deferred, post_mu, state_prices, total_payout, iterations_used, pending_id, last_iterate }. A non-deferred quote is directly executable; a deferred quote means the integrator needs more iterations than the per-block budget permits. Poll moxie_getPendingClearings until the pending id resolves.

POST moxie_swapContinuous

Submits a continuous swap. Body: { key, market_id, omega_a, omega_b, delta_amount, direction_code } where direction_code is 0 (Buy) or 1 (Sell). Returns a transaction hash.

POST moxie_provideContinuousLiquidity

Commits a range [omega_lo, omega_hi] with a weighting shape_code (and shape_param_a, optional shape_param_b) and a liquidity_budget. The caller’s swap_fee_bps share accrues to the position prorated by liquidity_budget across all LP positions in range for the duration of residency.

POST moxie_withdrawContinuousLiquidity

Closes an LP position and returns principal plus accrued fees.

POST moxie_resolveContinuousMarket

Terminates an active market. Only the creator may resolve. Every open ContinuousLpPosition for market_id is paid out (liquidity_budget + accrued_fees from custody back to owner) and removed; subsequent swapContinuous and provideContinuousLiquidity calls against the market return InvalidParameter. The market entry remains in state for historical queries until pruned.

POST moxie_pruneResolvedContinuousMarkets

Lifecycle close: removes resolved markets whose resolution block is older than CONTINUOUS_MARKET_RESOLUTION_RETENTION_BLOCKS = 10_000. Wall-clock duration depends on node cadence: about 5.56h at the default 2,000ms block time and 2.22h at the chained 800ms target. Open access: any nonce-holding account may submit once the retention threshold has elapsed.

GET moxie_getContinuousLpPosition

Reads a single LP position by position_id: range, shape, liquidity budget, accrued fees since last withdraw.

GET moxie_getContinuousLpPositionsByMarket

Observability read: all LP positions in a market. Supports dashboards and fee-accrual monitoring.

GET moxie_getContinuousLpPositionsByOwner

Paginated read of every LP position held by an owner across all continuous markets. Capped at 200 positions per call; callers page through larger inventories. Backs LP-dashboard workflows where a provider tracks accrued fees and ranges across concurrent markets.

GET moxie_getResolvedContinuousMarket

Returns the block number at which a given market_id was resolved, or indicates the market is not yet resolved. Backs audit tooling and the retention-window check before pruneResolvedContinuousMarkets.

GET moxie_getPendingClearings

Lists deferred quotes awaiting further integrator iterations. Each entry carries pending_id, last_iterate, and estimated blocks-to-completion.

Enum codes (wire)

grid_size_code0..=5
N8, N16, N32, N64, N128, N256. Wider grids are higher resolution at the cost of per-swap integrator budget.
generator_code0..=4
Quadratic, Entropy, Logarithmic, PowerMean2, ExponentialKernel. The generator sets the curvature of the cost function and the shape of the state-price response.
direction_code0..=1
Buy (0), Sell (1).
shape_code0..=2
PiecewiseConstant, Gaussian, Exponential. Determines how LP liquidity is weighted across the provided range.
swap_fee_bps0..=10000 (optional)
Basis-point slice of every Buy that accrues to LP positions prorated by liquidity_budget. Omit for a fee-less market.
LP flow (TypeScript)
typescript
import {
  Client, GridSizeCode, GeneratorCode,
  DirectionCode, ShapeCode,
} from "@moxie/sdk";

const moxie = new Client();

// 1. Creator opens a continuous market
await moxie.createContinuousMarket({
  key: KEY, market_id: MKT,
  omega_lo: "0",
  omega_hi: "1000000000000000000",
  grid_size_code: GridSizeCode.N64,
  generator_code: GeneratorCode.Entropy,
  initial_mu: ["500000000000000000"],
  swap_fee_bps: 30,
});

// 2. LP provisions a Gaussian range
await moxie.provideContinuousLiquidity({
  key: KEY, position_id: POS, market_id: MKT,
  omega_lo: "100000000000000000",
  omega_hi: "500000000000000000",
  shape_code: ShapeCode.Gaussian,
  shape_param_a: "300000000000000000",
  shape_param_b: "50000000000000000",
  liquidity_budget: "100000000000000000000",
});

// 3. Trader quotes + swaps (Buy direction pays fee)
const q = await moxie.quoteContinuous({
  market_id: MKT,
  omega_a: "100000000000000000",
  omega_b: "200000000000000000",
  delta_amount: "10000000000000000000",
  direction_code: DirectionCode.Buy,
});

if (!q.deferred) {
  await moxie.swapContinuous({
    key: KEY, market_id: MKT,
    omega_a: "100000000000000000",
    omega_b: "200000000000000000",
    delta_amount: "10000000000000000000",
    direction_code: DirectionCode.Buy,
  });
}

// 4. LP withdraws principal + accrued fees
await moxie.withdrawContinuousLiquidity({
  key: KEY, position_id: POS,
});
Observability (curl)
curl
$ curl -X POST http://localhost:8545 \
  -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,
      "method":"moxie_getContinuousLpPositionsByMarket",
      "params":[{"market_id":"0x..."}]}'

$ curl -X POST http://localhost:8545 \
  -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,
      "method":"moxie_getPendingClearings","params":[]}'

Predictions

Prediction events are binary or multi-outcome markets tied to real-world outcomes, settled in USDC. Events resolve in Phase 1 of each block, before any trades execute: this is event-atomic settlement, where prediction resolution and spot repricing happen in a single block. Resolution reprices the coupled brand token through the PW-AMM.

GET /api/v1/events

Lists prediction events. Filter by brand, status (Open, Closed, Resolved, Settled).

GET moxie.getPredictionOdds(eventId)

Retrieves prediction odds for a single event through JSON-RPC.

POST moxie.createEvent()

Creates a new prediction event through the signed native SDK path.

POST moxie.predictionMint()

Mints outcome shares for a prediction position. Specify prediction ID, event ID, outcome index, and amount.

POST moxie.predictionTrade()

Trades prediction shares through the signed native SDK path.

Event Object

outcomes string[]
Outcome labels. e.g. ["McGregor KO", "Decision", "Opponent"]
probabilities string[]
LMSR-derived probabilities for each outcome (18-decimal).
status string
OpenClosedResolvedSettled
resolvedOutcome number | null
Index of the winning outcome after resolution.
Create and trade a prediction
typescript
// Create event
const eventId = "0x<64-hex-event>";
const marketId = "0x<64-hex-market>";
const createTx = await moxie.createEvent({
  key: "0x<64-hex>",
  event_id: eventId,
  market_id: marketId,
  opens_at: 1743724800,
  closes_at: 1743811200,
  brand_id: "0x<64-hex-brand>",
  title: "McGregor vs Chandler",
});

// Mint YES shares
const mintTx = await moxie.predictionMint({
  key: "0x<64-hex>",
  prediction_id: "0x<64-hex-prediction>",
  event_id: eventId,
  outcome_index: 0,
  amount: "500000000000000000000",
});

// Check probabilities
const live = await moxie.getPredictionOdds(eventId);
console.log(live.yes_pct, live.no_pct);
// ["0.62...", "0.38..."]

Drops

VRF-based reward distributions. A creator funds a pool, sets a weight function and duration. At the designated block, the on-chain VRF selects winners weighted by stake. Winners claim rewards before the deadline.

GET /api/v1/drops

Lists drops. Filter by brand or status (Upcoming, Active, Revealing, Completed).

POST /api/v1/drops

Creates a new drop with reward pool, weight function, execution block, and claim deadline.

POST /api/v1/drops/{dropId}/claim

Claims winnings for a completed drop. Only callable by winners.

Weight Functions

Linear
Weight proportional to stake.
Sqrt
Square root of stake. Favors smaller stakers.
Log
Logarithmic. Most egalitarian.
Power
Quadratic. Rewards conviction.
Create a drop
typescript
const dropId = "0x<64-hex-drop>";
const dropTx = await moxie.dropCreate({
  key: "0x<64-hex>",
  drop_id: dropId,
  brand_id: "0x<64-hex-brand>",
  reward_pool: "10000000000000000000000",
  weight_function: "sqrt",
  execution_block: 900000,
  claim_deadline_block: 901000,
});

// Later: claim winnings
const claimTx = await moxie.dropClaim({
  key: "0x<64-hex>",
  drop_id: dropId,
});
List active drops
typescript
const drops = await moxie.getDrops();
const active = drops.filter((drop) => drop.status === "Active");

Personas

Belief-weighted character tokens tied to a parent brand. Each persona has an LMSR belief state coupled to the brand’s prediction markets. Shares trade on a bonding curve until graduation to a full brand token.

GET /api/v1/personas

Lists persona tokens. Filter by brand.

GET /api/v1/personas/{personaId}

Retrieves a single persona with belief weight, supply, price, and holder count.

POST /api/v1/personas/{personaId}/buy

Buys persona shares. Cost determined by the bonding curve.

POST /api/v1/personas/{personaId}/sell

Sells persona shares. Proceeds determined by the bonding curve.

Persona Object

beliefWeight string
LMSR belief parameter. Couples to prediction probabilities.
totalSupply string
Shares in circulation (18-decimal).
Buy persona shares
typescript
// List personas for UFC
const brandId = "0x<64-hex-brand>";
const personaId = "0x<64-hex-persona>";
const personas = await moxie.getPersonas(brandId);
// [{ name: "McGregor", price: "0.85..." },
//  { name: "Chandler", price: "0.42..." }]

// Buy shares
const quote = await moxie.personaBuyCost(personaId, "100000000000000000000");
const buyTx = await moxie.personaBuy({
  key: "0x<64-hex>",
  brand_id: brandId,
  persona_id: personaId,
  delta_shares: "100000000000000000000",
  max_cost: quote.net_cost,
});

// Sell shares
const sellTx = await moxie.personaSell({
  key: "0x<64-hex>",
  brand_id: brandId,
  persona_id: personaId,
  delta_shares: "50000000000000000000",
});

Accounts

Query account state: balances across all tokens, transaction history, staking positions, and KYC tier. Transfer tokens, stake to validators, and unstake.

GET /api/v1/accounts/{address}/balances

Lists all token balances for an account. Each entry includes token symbol, balance, and current price.

GET /api/v1/accounts/{address}/history

Paginated transaction history. Each transaction includes type, block, success status, and error message if failed.

Transfers and staking are native signed SDK mutations, not REST account routes.

KYC Tiers

ContenderLevel 1
Basic verification. Trading enabled.
EliteLevel 2
Enhanced verification. Higher limits.
ChampionLevel 3
Full verification. Event creation enabled.
LegendLevel 4
Maximum access. Governance participation.
Query account
typescript
const address = "0x<40-hex-address>";
const [balance, nonce, kyc] = await Promise.all([
  moxie.getBalance(address),
  moxie.getNonce(address),
  moxie.getKycLevel(address),
]);
console.log(balance, nonce, kyc.kycLevel);

const balances = await moxie.getTokenBalances(address);
balances.forEach(b => {
  console.log(b.token_id, b.balance);
});
Transfer tokens
typescript
const txHash = await moxie.transfer({
  key: "0x<64-hex>",
  to: "0x<40-hex-address>",
  amount: "500000000000000000000",
  token: "0x<64-hex-token>",
});
console.log(txHash);

Positions

Cross-margined clearinghouse positions. A single USDC-denominated margin pool backs spot, prediction, perpetual, and liquidity positions. Diversified portfolios require less capital because the clearinghouse understands brand correlation and offsets hedged exposure.

GET /api/v1/accounts/{address}/positions

Lists positions for an account. Filter client-side by market or kind (BrandSpot, BrandPrediction, Standalone).

Position Object

size string
Position size (18-decimal).
unrealizedPnl string
Unrealized profit/loss at mark price (18-decimal).
margin string
Required margin for this position (18-decimal).
Query positions
typescript
const positions = await moxie.getPositionsDetailed(
  "0x<40-hex-address>"
);

positions
  .filter((p) => p.kind === "BrandSpot")
  .forEach(p => {
  console.log(
    p.marketId,
    p.size,
    p.marginRequirement
  );
});

Governance

On-chain governance through ve$MOXIE vote-escrowed tokens. Proposals progress through Pending, Active, Passed, Rejected, and Executed states. Voting power is proportional to locked MOXIE amount and lock duration.

GET /api/v1/governance/proposals

Lists governance proposals. Filter by status or proposer.

POST /api/v1/governance/proposals

Submits a new governance proposal with title, description, and executable actions.

POST /api/v1/governance/proposals/{proposalId}/vote

Casts a vote on a proposal. Pass support: true/false and optional amount to weight.

Submit and vote
typescript
// Submit proposal
const prop = await moxie.governanceSubmit({
  proposer: "0x<40-hex-address>",
  title: "Reduce pool fees to 20bps",
  description: "...",
  actions: [{ type: "SetPoolFee", fee: 20 }],
});

// Vote
const vote = await moxie.governanceCastVote({
  voter: "0x<40-hex-address>",
  proposalId,
  support: true,
});

IP Graph

The IP licensing relationship graph. Nodes represent entities (brands, licensors, distributors). Edges represent licensing agreements, revenue splits, and IP transfer relationships with weights.

GET /api/v1/ip/graph

Returns the current IP graph as { nodes, edges, totalNodes, totalEdges }. Filter client-side by brand, entity, or relationship.

Traverse the graph
typescript
const graph = await moxie.getIpGraph();
const brandId = "0x<64-hex-brand>";
const nodes = graph.nodes.filter((n) => n.brandId === brandId);
const edges = graph.edges.filter(
  (e) => e.fromBrand === brandId || e.toBrand === brandId
);

edges.forEach(e => {
  console.log(e.fromBrand, "->", e.toBrand, e.relationship);
});

Chain

Chain-level queries: node health, block retrieval, transaction receipts, and historical state-root proofs. Blocks execute in three deterministic phases. The default block-time constant is 2,000ms; chained execution targets 800ms, while consensus tests still exercise the 600ms centerline.

GET /api/v1/chain/status

Returns chain ID, current block number, sync status, peer count, and pending transaction count.

GET /api/v1/chain/blocks/{blockNumber}

Retrieves a block by number. Use latest for the most recent block.

GET /api/v1/chain/tx/{hash}

Returns a transaction receipt when present; a missing receipt serializes as null. The SDK’s signed mutation helpers poll via waitForReceipt(txHash) by default.

POST moxie_getStateRoot

Returns the historical block-header state root at a hex block height plus the current retained chain window. Heights older than retained history fail closed with JSON-RPC code -32004 and a pruned history unavailable envelope carrying requested_height, chain_oldest_height, chain_newest_height, and pruned_count.

POST moxie_getTransactionReceipt

Returns the current bare receipt by tx hash. The Tier 1 SDK method is getTransactionReceipt(txHash); signed mutation helpers call the same receipt path through waitForReceipt(txHash). RpcReceipt carries optional camelCase settlementBatchRoot: string | null and events: RpcReceiptEvent[]. Terminal or single-chunk SettlementBatch receipts populate settlementBatchRoot; NativeTx::PayoutReturned receipts include a PayoutReturned event with payoutId, recipient, amount, and returnCode. A23 proof methods (moxie_getReceipt with includeProof and moxie_getReceiptsForBlock) are publicly registered; their RpcMerkleReceipt.digestInput mirrors settlementBatchRoot and commits receipt events through eventsRoot.

POST moxie_estimateGas

Per-tx gas estimation. EvmCall paths reserve the declared gas_limit at admission, reject underpriced max_fee_per_gas/max_priority_fee_per_gas caps against the current base fee, execute at the effective EIP-1559 gas price, and reconcile block gas to revm-metered receipt.gas_used after execution. Non-EVM variants still use their static consensus tiers.

POST moxie_estimateSettlementBatch

Settlement-job dry-run for the moat #1 primitive. Single named param { payload: SettlementBatchPayload }. Returns { gas_estimate: u64, manifest_root: 0x-prefixed 32-byte hex, validation: { ok: bool, errors: string[] }, chunked_mode: bool, is_terminal_chunk: bool, staging_complete: bool }. Per invariant I-12, dev-input failures return HTTP 200 with validation.ok = false rather than a JSON-RPC envelope error; reserved 4xx / Internal envelopes are transport-only. Public read class — no auth required. The gas heuristic constants are pub-exported in crates/moxie-rpc/src/types.rs: BASE_GAS = 21,000, GAS_PER_PAYOUT = 5,000, GAS_PER_MINT = 5,000, GAS_PER_BURN = 5,000, GAS_PER_ORACLE = 3,000, GAS_PER_MARGIN = 3,000, GAS_PER_CHUNK = 1,000.

POST moxie_submitSettlementBatch

Settlement-job write for the moat #1 primitive. Auth class: AuthWrite (mirrors moxie_submitSigned rate-limiting and auth). Mandatory Idempotency-Key header on every request (I-3). Bi-modal envelope: trusted-gateway auth-only mode { payload }, or client-side ECDSA signed mode { payload, signature: 0x-prefixed-hex, signer: 0x-prefixed-20-byte-hex, cryptographic_epoch?: number }. Half-pair envelopes (signature without signer or vice versa) return RpcErr::InvalidParams. The handler re-runs payload.validate_cheap_checks() and payload.compute_manifest_root() before mempool dispatch and rejects manifest-root mismatch. Dispatches via the same submit_signed_transaction() path as moxie_submitSigned: HEAL A1 active-suite verification plus the downgrade gate. Returns { tx_hash: 0x-prefixed 32-byte hex }; clients then call waitForReceipt(txHash) and read settlementBatchRoot on the terminal receipt. Returned payouts are submitted as signed NativeTx::PayoutReturned transactions and observed through receipt.events.

POST moxie_gasFeeData

Returns the live { baseFeePerGas, maxPriorityFeePerGas } envelope. Base-fee adjusts per block via the canonical Roughgarden 2021 update rule (±12.5% bound, denominator δ = 8, 1-wei wake-up bump, MIN_BASE_FEE_PER_GAS floor). maxPriorityFeePerGas is the nonzero deterministic suggestion; EvmCall mempool ordering derives its cleartext priority byte from the paid priority-fee cap.

POST moxie_getTerminalKernelState

Returns the terminal clearing-kernel snapshot: root registry, role-scoped authority grants and action nonces, ProductLegalProfile and TemplatePack registries, RiskGeneratorV1 snapshots, executable-depth certificates and consumed keys, release/recovery authorizations, recognized reliance instruments and envelopes, admitted AOT ledger, certified hot-market deltas/status, and bounded CPCAM adapter certificates. Sibling reads expose narrower views: moxie_getTerminalKernelRoot, moxie_getTerminalTemplatePacks, moxie_getTerminalRelianceInstruments, and moxie_getTerminalHotMarketStatus.

POST moxie_lowerClaimGraph

Deterministic source-layer preflight for product compilers. Single named param { program: ClaimProgramDefinition, graph: ClaimGraph, context: ClaimLoweringContext }. The node validates the program, graph, evidence, risk, reliance, and lowering context, then returns { program_id, graph_id, graph_root, compiler_version, aot } without mutating chain state. Consensus truth remains the lowered AdmissibleObligationTransition.

Chain info
typescript
const info = await moxie.health();
console.log(info.block, info.status);
// 847293  "healthy"

const block = await moxie.getBlock("latest");
console.log(block.transactionCount, block.hash, block.receiptsRoot);

const receipt = await moxie.getTransactionReceipt(txHash);
console.log(receipt.success);

const root = await moxie.call<{
  block_height: string;
  state_root: string;
  source: "block" | "state_root_history";
  chain_newest_height: string;
}>("moxie_getStateRoot", ["0x1234"]);
console.log(root.state_root);

// A23 proof APIs are registered: moxie_getReceipt(includeProof) and moxie_getReceiptsForBlock.
// Use getTransactionReceipt(txHash) when the current bare receipt is enough.

	// EIP-1559 gas surface (B7) — dynamic base-fee plus paid priority suggestion
const fee = await moxie.gasFeeData();
console.log(fee.baseFeePerGas, fee.maxPriorityFeePerGas);

	const est = await moxie.estimateGas(unsignedTx);
	console.log(est.gasLimit, est.maxFeePerGas);

const terminal = await moxie.terminal().root();
console.log(terminal.terminal_kernel_root);

// Moat #1 — settlement-job dry-run + signed submit
const dryRun = await moxie.call<{
  gas_estimate: number;
  manifest_root: string;
  validation: { ok: boolean; errors: string[] };
  chunked_mode: boolean;
  is_terminal_chunk: boolean;
  staging_complete: boolean;
}>("moxie_estimateSettlementBatch", { payload: settlementPayload });
if (!dryRun.validation.ok) throw new Error(dryRun.validation.errors.join(", "));

// Auth-only trusted-gateway mode
const submitted = await moxie.call<{ tx_hash: string }>(
  "moxie_submitSettlementBatch",
  { payload: settlementPayload },
  { idempotencyKey: "settle-2026-04-27-001" },
);
const rcpt = await moxie.waitForReceipt(submitted.tx_hash);
console.log(rcpt.success, rcpt.settlementBatchRoot, rcpt.events);
// settlementBatchRoot is populated for terminal/single-chunk SettlementBatch.
// PayoutReturned receipts expose the committed return event in rcpt.events.

Perpetuals

Perpetual contracts on IP-linked tokens. Open long or short positions, receive periodic funding payments, and close at any time. Funding rates are computed from mark-index price divergence and exposed on the perp market read model; the exact wall-clock interval follows configured block cadence.

GET /api/v1/perps

Lists perpetual markets with funding rates, mark/index prices, open interest, and funding interval. Opening and closing positions are signed SDK mutations.

Body Parameters

market_id string required
32-byte market identifier for the perpetual market.
is_long boolean required
true for long, false for short.
size string required
Position size in raw 18-decimal wire format.
persona_slug string required
Persona slug used by the native transaction builder.
collateral_amount string required
Collateral amount in raw 18-decimal wire format.
GET /api/v1/perps/{market_id}/positions/{address}

Reads a specific perpetual position. Closing positions is the signed perpClose() SDK mutation.

Body Parameters

market_id string required
32-byte market identifier.
address string required
20-byte account address.

Funding is visible on each PerpMarket; perpFunding() submits the funding-settlement native transaction when an operator needs to crystallize funding.

Funding Object

currentRate string
Current funding rate per block (18-decimal). Positive = longs pay shorts.
nextSettlement number
Block number of next funding settlement.
markPrice string
TWAP mark price (18-decimal).
indexPrice string
Spot index price (18-decimal).
Open a perpetual position
typescript
// Open a long on a perpetual market
const marketId = "0x<64-hex-market>";
const openTx = await moxie.perpOpen({
  key: "0x<64-hex>",
  market_id: marketId,
  is_long: true,
  size: "1000000000000000000000",
  collateral_amount: "500000000000000000000",
  persona_slug: "mcgregor",
});
console.log(openTx);

// Check funding rate
const markets = await moxie.getPerpMarkets();
const market = markets.find((m) => m.market_id === marketId);
console.log(market?.funding_rate, market?.funding_rate_negative);

// Close the position
const closeTx = await moxie.perpClose({
  key: "0x<64-hex>",
  market_id: marketId,
  size: "1000000000000000000000",
  is_long: true,
});
console.log(closeTx);

Contingent Orders

Event-contingent order state is exposed as a read model per account. The current TypeScript write helper is conditionalOrder() for price-triggered orders with optional event context; stop-event and parlay state appear in the pending-order read model as the native executor matures.

GET /api/v1/orders/contingent/{address}

Lists pending contingent, stop-event, and parlay orders for a 20-byte account address.

Body Parameters

address string required
20-byte account address whose pending orders should be returned.
market_id string required
32-byte market identifier on returned order rows.
condition object required
Executor-rendered condition for contingent, stop-event, or parlay orders.
POST moxie.conditionalOrder()

Submits a signed conditional order through the SDK/native transaction path.

Body Parameters

market_id string required
32-byte market identifier.
trigger_price / limit_price string required
Raw 18-decimal trigger and execution prices.
quantity / is_buy / event_id mixed required
Signed order side, size, and optional event context.
GET moxie.getContingentOrders(address)

Reads all pending contingent-order families for the account; clients filter by type.

Body Parameters

address string required
20-byte account address whose pending order families should be returned.
type string response field
Returned order family: contingent, stop_event, or parlay.
GET /api/v1/orders/contingent/{address}

Lists all active contingent, stop-event, and parlay orders for the supplied account.

Contingent order
typescript
// Place a signed conditional order
const txHash = await moxie.conditionalOrder({
  key: "0x<64-hex>",
  market_id: "0x<64-hex-market>",
  trigger_price: "2300000000000000000",
  limit_price: "2250000000000000000",
  quantity: "500000000000000000000",
  is_buy: true,
  event_id: "0x<64-hex-event>",
});

// Read pending contingent-family orders
const pending = await moxie.getContingentOrders(
  "0x<40-hex-address>"
);
Parlay order
typescript
const parlays = pending.filter(
  (order) => order.type === "parlay"
);

parlays.forEach((order) => {
  console.log(order.order_id, order.market_id, order.condition);
});

Autonomous Events

Self-resolving prediction events are submitted through the signed createAutonomousEvent() SDK helper. The current node does not expose a REST create route; REST observability should be layered on the event read model as parity work.

POST moxie.createAutonomousEvent()

Creates a signed CreateAutonomousEvent native transaction.

Body Parameters

description string required
Human-readable event description.
affected_tokens string[] required
Token IDs affected by the event.
factor_loadings string[] required
FixedPoint loading per affected token.
resolution_criteria string required
Condition text evaluated by the resolution/oracle path.
base_probability string required
Raw 18-decimal FixedPoint probability.
time_horizon_blocks number required
Resolution horizon in blocks.

Event read-side visibility is served through getEvents() and /api/v1/events.

Create autonomous event
typescript
// Self-resolving fight outcome event
const txHash = await moxie.createAutonomousEvent({
  key: "0x<64-hex>",
  description: "UFC 295 Main Event Winner",
  affected_tokens: ["0x<64-hex-token>"],
  factor_loadings: ["1000000000000000000"],
  resolution_criteria: "ufc.event.295.main.winner != null",
  base_probability: "500000000000000000",
  lmsr_liquidity_b: "1000000000000000000000",
  time_horizon_blocks: 200,
});
console.log(txHash);

// Event resolves automatically when
// oracle posts the fight result
const events = await moxie.getEvents();
console.log(events.length);

Reflexivity

The calibration and risk-reflexivity surfaces expose the reflexivity coefficient ρ (rho): a measure of how strongly prediction market outcomes feed back into the brand token price. When ρ is high, event resolution has outsized price impact; when low, the brand token trades independently of prediction markets.

GET /api/v1/calibration

Returns the current calibration state, including reflexivity diagnostics and OI cap controller state.

ReflexivityResult Object

rho string
Reflexivity coefficient (18-decimal). Range [0, 1]. Higher values indicate stronger prediction-price coupling.
windowBlocks number
Observation window in blocks over which ρ was computed.
eventContributions array
Per-event contribution to ρ: { eventId, weight, priceImpact }.
couplingMode string
Active coupling mode derived from ρ. One of PwAmm, BinaryPayoff, Logit.
GET /api/v1/risk/reflexivity

Returns the REST reflexivity diagnostic view. Use moxie_getCalibration for the consensus calibration state.

Query reflexivity
typescript
const calibration = await moxie.getCalibration();
const reflexivity = calibration.reflexivity as {
  rho?: string;
  severity?: string;
};
console.log(
  reflexivity.rho,
  reflexivity.severity
);

// REST diagnostic view
const risk = await moxie.getRiskReflexivity();
console.log(risk.reflexivity.reflexivity_score);

Circuit Breakers

The CircuitBreakerState endpoint reports node-wide halt state. Circuit breakers trigger on extreme price moves, abnormal reflexivity spikes, or governance action. During a halt, new orders are rejected; existing positions remain open but cannot be modified.

GET /api/v1/circuit-breaker

Returns the node-wide current CircuitBreakerState.

CircuitBreakerState Object

is_halted boolean
Whether trading is currently halted.
reason string | null
Halt reason: PriceMove, ReflexivitySpike, Governance, or null if not halted.
halt_triggered_block number | null
Block number when the halt was triggered.
blocks_remaining number | null
Number of blocks remaining in the current halt window.
epoch_start_price string
Epoch start price in raw 18-decimal wire format.
GET moxie.getCircuitBreaker()

TypeScript SDK JSON-RPC helper for the same state.

Check circuit breaker
typescript
const cb = await moxie.getCircuitBreaker();

const halted = Boolean(cb.is_halted ?? cb.halted);
const blocksRemaining = Number(cb.blocks_remaining ?? 0);

if (halted) {
  console.log(
    `Halted: ${cb.reason}`,
    `blocks remaining ${blocksRemaining}`
  );
} else {
  console.log("Trading active");
}

Coupling Modes

The clearing engine supports three coupling modes that determine how prediction event outcomes affect the brand token price. The active mode is selected automatically based on the reflexivity coefficient ρ and can be overridden by governance.

GET /api/v1/calibration/lmsr/{market_id}

Returns LMSR calibration for a market; coupling-mode governance remains a consensus-layer concept rather than a dedicated REST route.

CouplingMode Variants

PwAmm default
Probability-Weighted AMM. Brand price adjusts via a bounded geometric function of prediction probabilities. Active when ρ < 0.5.
BinaryPayoff EKF coupling
Extended Kalman Filter coupling. Brand token behaves as a binary payoff instrument: price converges toward 1.0 or 0.0 based on the dominant prediction outcome. Active when ρ ≥ 0.7. Used for high-stakes single-event brands.
Logit logit-space coupling
Logit-space coupling. Prediction probabilities are mapped through a logit transform before affecting brand price, compressing extreme probabilities and smoothing price dynamics. Active when 0.5 ≤ ρ < 0.7.

Calibration Object

oi_cap_controller string
PID-style controller output for open-interest caps.
reflexivity string
Reflexivity diagnostic record from the consensus state.
calibration.status object
REST LMSR calibration status for a specific market.
governance override consensus state
Tracked in the consensus layer; no dedicated REST route currently exists.
Query coupling mode
typescript
const calibration = await moxie.getCalibration();
const reflexivity = calibration.reflexivity as { severity?: string };
console.log(reflexivity.severity);
// "Elevated"

console.log(calibration.oi_cap_controller.phi);
// Current OI cap controller output

const lmsr = await moxie.getLmsrCalibration(
  "0x<64-hex-market>"
);
console.log(lmsr.calibration.status);

Mutual Information

The MutualInformationEstimator computes the mutual information (MI) between prediction event outcomes and brand token price movements. The MI-derived κ (kappa) parameter controls the coupling strength in the PW-AMM: higher MI means tighter coupling between predictions and price.

GET /api/v1/correlations/recent

Returns recently updated correlation estimates used by the intelligence layer.

MutualInformation Object

mi string
Mutual information estimate in nats (18-decimal).
kappa string
MI-derived coupling strength parameter (18-decimal). Used by the PW-AMM to scale prediction-price coupling.
sampleCount number
Number of observation pairs used in the MI estimate.
confidence string
Bootstrap confidence interval width (18-decimal). Smaller is better.
GET /api/v1/intelligence/snapshot

Returns top correlations and cohort summary statistics.

Query mutual information
typescript
const recent = await moxie.getCorrelationsRecent();
recent.correlations.forEach((edge) => {
  console.log(edge.event_a, edge.event_b, edge.rho, edge.n);
});

// Aggregate intelligence view
const snapshot = await moxie.getIntelligenceSnapshot();
console.log(snapshot.snapshot.cohort.mean_rho);

Soulbound Status

Non-transferable reputation credentials issued to accounts based on on-chain clearing activity. SoulboundStatus tokens are ERC-5192-style: they live in a wallet permanently and represent earned standing in the clearing network. Badges unlock tier promotions, governance weight boosts, and drop eligibility.

GET /api/v1/participants/{address}/badges

Lists all soulbound badges held by an account.

GET /api/v1/participants/{address}/profile

Returns the participant engagement profile that badge issuance is based on.

Badge Types

EarlyAdopter
Issued to accounts active in the first 10,000 blocks.
PredictionStreak
Awarded for 10+ consecutive correct prediction outcomes.
LiquidityProvider
Issued to accounts providing liquidity for 30+ consecutive days.
GovernanceParticipant
Awarded for voting on 5+ governance proposals.
BrandChampion
Issued to top-10 holders of a brand token for 90+ consecutive days.

SoulboundStatus Object

badgeId string
Unique badge identifier.
badgeType string
Badge type name.
issuedAtBlock number
Block number when the badge was issued.
locked boolean
Always true. Soulbound tokens cannot be transferred.
Query soulbound badges
typescript
const address = "0x<40-hex-address>";
const badgesRes = await fetch(
  `/api/v1/participants/${address}/badges`
);
const badges = await badgesRes.json();

badges.badges.forEach(b => {
  console.log(b.badge_type, b.earned_at);
});
// "EarlyAdopter"  1024
// "PredictionStreak"  48201

// Pair with participant profile
const profileRes = await fetch(
  `/api/v1/participants/${address}/profile`
);
const profile = await profileRes.json();
console.log(profile.composite_score);

Temperature Compliance

The TemperatureComplianceMapping defines regulatory graduation thresholds for brand tokens. Temperature graduation (Cold → Warm → Hot) is the clearing network's regulatory ramp: Cold brands trade with minimal KYC and no leverage; Warm brands unlock perpetuals and higher limits; Hot brands require full accredited-investor attestation and enable maximum leverage. This endpoint exposes the mapping between temperature regimes and required compliance checks, KYC tiers, and position limits.

GET /api/v1/tokens/{token_id}/temperature

Returns the current execution regime and compliance requirements for a token.

The TypeScript SDK exposes the same state via getTokenTemperature(tokenId).

TemperatureComplianceMapping Object

regime string
Cold, Warm, or Hot.
minKycTier string
Minimum KYC tier required: Contender, Elite, Champion, or Legend.
maxPositionSize string
Maximum position size in USDC (18-decimal).
maxLeverage number
Maximum leverage for perpetual contracts.
requiredChecks string[]
Compliance checks required: e.g. ["AML", "Sanctions", "AccreditedInvestor"].
perpEnabled boolean
Whether perpetual contracts are available for brands in this regime.
parlayEnabled boolean
Whether parlay orders are available for brands in this regime.
Query compliance mapping
typescript
const tokenId = "0x<64-hex-token>";
const temp = await moxie.getTokenTemperature(tokenId);

console.log(
  temp.regime,
  temp.required_compliance_domains
);
// "Cold" ["ConsumerProtection", "AML"]

Mass-Moxie Bridge

The bridge has two directions. Inbound: a Mass kernel signs a MassIdentityAttestation { attestor, subject, kyc_level, jurisdiction, expiry_block, signature }; the Moxie chain verifies it against a genesis-pinned Mass public key (updatable only via Moxie governance, never discovered from the attestation itself), and the subject’s KYC tier is upgraded on-chain. Per-subject monotonic issued_at_block blocks downgrade-rollback replay. A ComplianceGatePayload carries {brand_id, target_stage, composed_tensor_hash, verdict, expires_at, authority, nonce} as a consensus-affecting NativeTx: absent or expired Approved gates block market promotion past HybridAmmClob; a Rejected gate at Warm+ demotes the market back to EquilibriumAmm.

Outbound: MassObservationRelay runs under a configured bridge mode and produces signed POST /v1/corpus/observe requests to the Mass kernel (OAuth bearer from MOXIE_BRIDGE_TOKEN, or mTLS). Aggregation emits per-epoch jurisdiction roll-ups, never trade-level data. Revenue distribution flows through Mass with harbor-level withholding computed against the composed compliance tensor; Moxie anchors the returned Merkle root via RevenueDistribute and a claim contract validates Merkle proofs against the stored root.

A universal correlation thread corridor_id = blake3(u32_le(|ik|) ‖ ik ‖ u32_le(|tx|) ‖ tx ‖ entity_32 ‖ u64_le(asof)) threads the five cross-kernel surfaces: ComplianceQuery, ComplianceAssertion, AttestationProof, MassObservation, and the Moxie 3PC operation_envelope. The current REST surface is /api/v1/corridors/id, /status, /preflight, and /trace/{cid}. Every kill path routed through the bridge traces back to an accepted contract version, a triggered policy code, a dispute or safety case, or a compliance verdict; regulator takedowns require an F38 CeremonyOverrideReceipt participating in block commit. No kill-by-Slack-DM.

POST moxie.submitMassAttestation()

Submits a Mass identity attestation to the Moxie chain via JSON-RPC. The attestation is a signed credential from a Mass kernel proving that an identity has passed a specific compliance check. Once attested, the Moxie account is upgraded to the corresponding KYC tier.

Body Parameters

subject string required
Moxie account address to attest.
attestor string required
Mass kernel attestor identifier.
kyc_level / jurisdiction / expiry_block / signature mixed required
Consensus attestation fields verified against the pinned Mass public key.
POST /api/v1/compliance/preflight

Checks whether the target entities are likely to pass the compliance tensor for a specific operation. The chain remains the binding authority at admit time.

Body Parameters

entity_ids string[] required
One or more 32-byte entity IDs to compose through the compliance tensor.
purpose string required
Canonical opcode or method name, e.g. NativeTx::PerpOpen or moxie_submitSigned.
GET moxie.getKycLevel(address)

Reads the account KYC level after attestations have been applied.

Preflight Response

allowed boolean
Whether the chain would likely admit the target purpose if submitted immediately.
reasons string[]
Per-domain reason records with stable moxie.compliance.* codes.
commitment string
Commitment over the composed tensor slice for follow-up writes.
asof_block / ttl_ms number
Block height and freshness window for the preflight verdict.
Submit Mass attestation
typescript
// Bridge a Mass KYC attestation to Moxie
const subject = "0x<40-hex-address>";
const attestTx = await moxie.submitMassAttestation({
  key: "0x<64-hex>",
  attestor: "0x<64-hex-attestor>",
  subject,
  kyc_level: "L2",
  jurisdiction: "SYC",
  expiry_block: 1200000,
  signature: "0x<signature>",
});
console.log(attestTx);
Check compliance gate
typescript
// Can this account open a perp?
const gate = await moxie.preflightCompliance({
  entity_ids: ["0x<64-hex-entity>"],
  purpose: "NativeTx::PerpOpen",
  jurisdiction: "SYC",
});

if (gate.allowed) {
  console.log("Cleared for perp trading");
} else {
  console.log(
    "Blocked:",
    gate.reasons.map((reason) => reason.code)
  );
}

// Read the resulting account tier
const kyc = await moxie.getKycLevel(subject);
console.log(kyc.kycLevel);

WebSockets

Real-time subscriptions over WebSocket. The TypeScript SDK exposes connectBlockSubscription(wsUrl, onBlock) for moxie_subscribe("newBlocks"), including reconnect backoff and decimal/hex block-number parsing. The broader WsClient with authentication and topic routing remains the parity target.

Channels

orderbook:{marketId}
Order book depth updates. Streamed after each block.
trades:{marketId}
Trade feed. Emitted for each executed swap or order fill.
blocks
New block notifications at the node's configured block cadence.
account:{address}
Balance and position changes for an account.
perp:{brandId}
Perpetual funding rate and mark price updates.
reflexivity:{brandId}
Reflexivity coefficient (ρ) and coupling mode changes.
circuit-breaker
Circuit breaker halt and resume events across all brands.

Connection URL

Pass an explicit node WebSocket URL such as wss://api.moxie.xyz or ws://localhost:8545. The current SDK helper is not derived from baseUrl.

Real-time subscriptions
typescript
import { connectBlockSubscription } from "@moxie/sdk";

// Stream new blocks through moxie_subscribe("newBlocks")
const ws = connectBlockSubscription(
  "wss://api.moxie.xyz",
  (block) => {
    console.log("Block", block.number, block.hash);
  }
);

// Close when the view unmounts.
ws.close();

SDK Installation

The official TypeScript SDK wraps the JSON-RPC surface with SDK-owned wire types, named methods, typed errors, retry logic for HTTP and JSON-RPC rate limits, client-side signer injection, idempotent native mutations, compliance preflight on supported mutation surfaces, A27 validation preflight, receipt polling, getBrandExperiences(), typed merch order receipts, PTJC racing, terminal-kernel resources, expanded leaderboard types, the webapp compatibility facade, and the block-subscription helper used by the webapp. The Rust and Python SDKs expose matching Tier 1 resources for brand experiences, merch order receipts, racing, settlement, gas, and terminal kernel access plus raw RPC escape hatches for the registered catalog; their continuous-market helpers mirror the consensus MAX_ORDER_SIZE cap before transport. For Rust release dry-runs, moxie-types must publish before moxie-sdk because the SDK depends on the pinned protocol type crate. The conformance corpus and parity tooling keep the SDK surface aligned with the node; scripts/sdk-parity-check.mjs covers registered methods, racing methods, and REST surfaces. Full topic-routed WebSockets remain tracked as parity work.

Requirements

Node.js
≥ 18.0.0
TypeScript
≥ 5.6.0

Client Options

apiKey string optional
Bearer token or API key for server-to-server auth.
signer Signer optional
Client-side native transaction signer.
baseUrl string optional
Default: http://localhost:8545
timeoutMs number optional
Request timeout in ms. Default: 30000.
maxRetries number optional
Retry count for 429, 5xx, JSON-RPC rate limits, timeouts, and retryable network errors. Default: 3.
Install
terminal
$ npm install @moxie/sdk@rc   # v1.0.0-rc.1
Publish dry-run order
terminal
$ cargo publish -p moxie-types --dry-run
$ cargo publish -p moxie-sdk --dry-run  # after moxie-types is published at the pinned version
Full configuration
typescript
import { Client } from "@moxie/sdk";

const moxie = new Client({
  apiKey: "mxat_...",
  baseUrl: "https://api.moxie.xyz",
  timeoutMs: 15000,
  maxRetries: 5,
});

Amount Utilities

The SDK exports fixed-point helpers for converting between human-readable decimal strings and the 18-decimal raw wire format used by the protocol. Always use these instead of manual arithmetic.

Raw wire amounts are strings because they exceed JavaScript’s Number.MAX_SAFE_INTEGER. Mutating SDK methods send raw wire amounts; convert display input before submitting writes.

Conversions
typescript
import {
  coerceFixedPointString,
  formatFixedPointRaw,
  parseFixedPointDecimal,
} from "@moxie/sdk";

// Human → Wire
parseFixedPointDecimal("1000.5");
// "1000500000000000000000"

// Wire → Human
formatFixedPointRaw("2470000000000000000");
// "2.47"

// Validate raw wire value
coerceFixedPointString("184201000000000000000000");
// "184201000000000000000000"