The taker client is a thin wrapper over these endpoints. Base URL is the relayerUrl in your config; the shared testnet relayer is https://sparrow-relayer.dennis-furrer.workers.dev. Conventions:
  • All amounts are raw USDC strings (6 decimals); all odds and probabilities are basis points.
  • Errors are {"error": string} with an optional machine code; the client surfaces error as the thrown message.
  • POST endpoints are rate limited per IP (default 60/min, HTTP 429) and return 503 {"error": "relayer paused"} while the admin kill switch is on.

POST /quote

Prices a leg set from live Hyperliquid mids, runs the correlation engine and risk limits, builds the ParlayOrder with the vault as maker, and signs the maker side. The client sends only which legs, never odds. Request
{
  "legs": [
    {"marketId": 101, "outcome": 1},
    {"marketId": 205, "outcome": 1}
  ],
  "stake": "25000000",
  "taker": "0x1b7E2a4Fc8b3D0a95C2fE4d9A61b0c37D4E8f612"
}
legs
array
required
1 to 10 legs (relayer MAX_LEGS), each {marketId, outcome} with outcome 0 or 1.
stake
string
required
Raw USDC. Defaults: min "1000000" (1 USDC), max "5000000000" (5,000 USDC).
taker
string
required
Taker wallet address.
takerNonce
string
Optional; a random 248-bit nonce is generated when omitted.
Response 200
{
  "order": {
    "taker": "0x1b7E2a4Fc8b3D0a95C2fE4d9A61b0c37D4E8f612",
    "maker": "0x807c7cb41573b8B7d3E52E3F37410A0a8eDA4fc0",
    "stake": "25000000",
    "makerCollateral": "60500000",
    "makerNonce": "412398...554",
    "takerNonce": "998214...031",
    "deadline": "1782951000",
    "protocolFeeBps": 100,
    "builderFeeBps": 25,
    "builder": "0x4Fb2...9c1A",
    "legs": [
      {"marketId": 101, "outcome": 1},
      {"marketId": 205, "outcome": 1}
    ]
  },
  "makerSig": "0x8f3a...1b01",
  "quote": {
    "payout": "85187500",
    "makerCollateral": "60500000",
    "combinedOddsBps": "34500",
    "netStake": "24687500",
    "legs": [
      {"marketId": 101, "outcome": 1, "impliedProbBps": 5400},
      {"marketId": 205, "outcome": 1, "impliedProbBps": 6100}
    ]
  },
  "correlation": {
    "independentOddsBps": "30350",
    "adjustedOddsBps": "33120",
    "jointProbBps": 3019,
    "reductionBps": "0",
    "clusters": [
      {"key": "solo:101", "driver": "Independent", "rho": 0, "marketIds": [101], "independentProbBps": 5400, "jointProbBps": 5400},
      {"key": "solo:205", "driver": "Independent", "rho": 0, "marketIds": [205], "independentProbBps": 6100, "jointProbBps": 6100}
    ]
  },
  "margin": null
}
The order deadline is 600 seconds out. margin is null under isolated accounting; see Margin for the cross-mode shape. Errors
StatusBodyMeaning
400{"error": "..."}Malformed request (bad legs, stake, or address)
422{"error": "...", "code": "mutually_exclusive"}Legs are outcomes of the same HL question; can never win
422{"error": "...", "code": "duplicate_leg"}Same market twice
422{"error": "no live price for market 101"}Leg has no HL mid right now
422{"error": "...", "code": "<risk code>", "marketId": 101}Risk limit hit: stake bounds, max odds, vault utilization, per-market exposure cap
502{"error": "could not fetch HL prices"}Hyperliquid unreachable
502{"error": "could not read vault capacity"}RPC failure reading the vault

POST /submit

Relays the co-signed order on-chain: simulates ParlayEscrow.submitParlay, then sends it from the relayer’s key (gasless for both signers). Request
{
  "order": { "...": "the serialized order from /quote, unmodified" },
  "makerSig": "0x8f3a...1b01",
  "takerSig": "0x72cd...9e1c"
}
Response 200
{
  "txHash": "0x5b1e0d7c33baf2a6f1f4a2f8f0f9f3f76a8f2b1e0d7c33baf2a6f1f4a2f8f0f9",
  "parlayId": "42"
}
Errors
StatusBodyMeaning
400{"error": "malformed order"}Order does not deserialize
422{"error": "<revert reason>"}On-chain revert: expired deadline, used nonce, bad signature, insufficient allowance or balance
503{"error": "submission temporarily unavailable"}RPC or network failure (retryable)

POST /cashout

Quotes and signs a buy-back to close a live parlay early. Prices the remaining legs from live HL mids through the same correlation engine, then applies the buy-back spread (default 300 bps). Execution is the taker’s own transaction: ParlayEscrow.cashOut with the returned signature. Request
{
  "parlayId": 42,
  "taker": "0x1b7E2a4Fc8b3D0a95C2fE4d9A61b0c37D4E8f612"
}
Response 200
{
  "parlayId": 42,
  "cashValue": "31250000",
  "quoterNonce": "731442...119",
  "deadline": "1782950520",
  "sig": "0xc41b...77aa",
  "jointProbBps": "4180",
  "pot": "84187500"
}
deadline is 120 seconds out. cashValue = pot * jointProb * (1 - spread), clamped to the escrowed total. Errors
StatusBody
400{"error": "bad request"}
403{"error": "not your parlay"}
404{"error": "unknown parlay"}
409{"error": "already settled"}
422{"error": "no live price for market 101"}
502{"error": "could not read parlay"} or {"error": "could not fetch HL prices"}

GET /margin

Public margin-engine transparency: the live accounting mode plus the isolated-vs-cross comparison. Works even while the relayer is paused. Append ?detail=1 for the per-position book and netting clusters. Response 200
{
  "mode": "isolated",
  "creditHaircutBps": 2000,
  "vault": {
    "totalAssets": "250000000000",
    "locked": "18500000000",
    "utilizationCapBps": 8000,
    "capacity": "200000000000"
  },
  "book": {
    "positions": 14,
    "isolatedLocked": "18500000000",
    "worstCaseLocked": "13100000000",
    "relief": "5400000000",
    "securedCredit": "4320000000",
    "effectiveLocked": "14180000000",
    "nettedComponents": 2,
    "exact": true
  },
  "headroom": {
    "isolated": "181500000000",
    "cross": "185820000000"
  }
}
With ?detail=1, two extra fields:
{
  "positions": [
    {"id": 40, "makerCollateral": "1400000000", "legs": [{"marketId": 205, "outcome": 1}]},
    {"id": 41, "makerCollateral": "900000000", "legs": [{"marketId": 207, "outcome": 1}]}
  ],
  "clusters": [[40, 41]]
}
Errors: 502 {"error": "could not compute margin state"}, 503 when the escrow is unconfigured.

GET /health

Relayer readiness. Also works while paused. Returns HTTP 200 when ok, 503 otherwise, always with the same body shape: Response
{
  "ok": true,
  "paused": false,
  "quoterAuthorized": true,
  "checks": {
    "configured": true,
    "rpc": true,
    "hl": true,
    "vault": true
  }
}
ok
boolean
Configured, RPC and HL reachable, a quoter authorized on the vault, and not paused.
paused
boolean
Admin kill switch. POST endpoints return 503 while true.
quoterAuthorized
boolean | null
Whether any configured quoter key is authorized on the vault; null when the check could not run.
checks
object
Individual probes: configured, rpc, hl, vault.

Deployment flags that shape responses

Set in the relayer’s wrangler.toml (defaults shown); useful when running your own stack:
FlagDefaultEffect
HL_TESTNET"false"Price from HL testnet instead of mainnet HIP-4
PROTOCOL_FEE_BPS / BUILDER_FEE_BPS100 / 25Fees taken from the stake
SPREAD_BPS200Vault edge on odds
CASHOUT_SPREAD_BPS300Buy-back spread on cash-outs
MIN_STAKE / MAX_STAKE1 / 5,000 USDCStake bounds
MAX_LEGS10Max legs per parlay
MAX_ODDS_BPS10000000 (1000x)Max combined odds
MAX_UTILIZATION_BPS8000Vault utilization cap for quoting
MAX_MARKET_EXPOSURE_BPS3000Per-market share of NAV across the book
MARGIN_MODE / CREDIT_HAIRCUT_BPSisolated / 2000Cross-margin toggle and haircut
RATE_LIMIT_PER_MIN60Per-IP POST rate limit