API

Read markets, accounts, and the chain, stream live data, and submit signed transactions.

Basics

  • Base URL: https://api.jeets.trade
  • Amounts are micro-USDG and prices are micro-USD, as integers: 1 USDG is 1000000.
  • Accounts are Robinhood Chain (EVM) addresses, written lowercase as 0x and 40 hex digits; the API accepts checksummed ones too. Hashes, signatures, and session keys are 0x-prefixed hex.

REST

RequestReturns
GET /statuschainId, entries (transactions so far), prices, pool, mempool size
GET /marketsPrices, open interest, pool, payout queue, fees (withdrawalFee), chainId, minNotional (smallest order value), maxSideGap; per market longCap/shortCap and longRoom/shortRoom (new notional that fits on each side now; null is unlimited). Order clients need minNotional and the room fields.
GET /account/:addressLive balance, nextNonce, session key and agentExpiresMs, positions with PnL, queued winnings
GET /positionsEvery open position on the exchange, largest first, valued at the live price
GET /prices/history?market=BTC&windowMs=3600000&points=600&endMs=…Oracle price history for a stretch ending at endMs (default now, at most a week back), led by the last price before it; firstMs is the first recorded price
GET /markets/volume?windowMs=86400000Opened volume and trade count per market over a window (default 24h)
GET /stats?windowMs=86400000&bucketMs=1800000Exchange totals, activity per time bucket, volume per market, top traders
GET /trades?limit=40Recent opens, closes, and liquidations
GET /txs?before=&limit=25Transactions, newest first; before is a seq. Each has its seq, hash, kind, signer, tx, receipt, the prices and timestampMs it ran at, and where it was written on Robinhood Chain (chainTxHash, chainBlock, chainLogIndex; null until it is)
GET /blocks?before=&limit=25Robinhood Chain blocks holding Jeets transactions, newest first, one row per ledger write (txHash, block, fromSeq, toSeq, kinds); before is a Robinhood Chain block number
GET /blocks/:number, /blocks/latestA Robinhood Chain block: its ledger writes (records) and the Jeets transactions in them (txs)
GET /tx/:hashA transaction, as in /txs; withdrawals add payouts, the vault payment on Robinhood Chain (txHash, status)
GET /address/:addressCommitted account view with trading stats and withdrawals (each with the vault payment’s txHash once sent)
GET /address/:address/txs?before=&limit=An account’s transactions, newest first; before is a seq
GET /evmWhere Jeets lives on Robinhood Chain: chainId, rpcUrl, explorerUrl, the vault and USDG token addresses (null on a node without deposits), and the ledger contract
POST /txSubmit a signed transaction; returns its hash

Paged lists take limit (default 25, at most 100) and before, an exclusive cursor: pass the last item’s seq (or, for /blocks, its block) to get the next page.

WebSocket

For live prices, markets, accounts, open positions, transactions, Robinhood Chain blocks, and trades, connect to /ws. See WebSocket.

Deposits

There is no deposit endpoint. Approve USDG to the vault, then call deposit(amount) on the vault from the account’s own wallet (addresses from GET /evm). The node credits the amount once it sees the vault’s Deposited log. USDG sent to the vault with a plain transfer isn’t credited.

Signing transactions

A transaction names the chain (chainId from GET /status or /markets: the Jeets chain, not the EVM chain id), the account, the account’s next nonce (nextNonce from GET /account/:address, which counts transactions already queued), and an action: open, close, withdraw, or setAgent, and for the admin account only, setLimits, setSideGap, and fundPool ({ "type": "fundPool", "amount": 5000000000 }, signed text action: fund pool / amount: 5000.000000 USDG). Build the text below and sign it, then post it.

  • The text is UTF-8, with \n line breaks and no trailing newline. Amounts have 6 decimals. The chain id is 16 hex digits without 0x. The account is lowercase.
  • Wallet signatures are personal_sign (EIP-191) over the text: the 65-byte secp256k1 signature as 0x hex. The node recovers the signer from it, so it must be the account’s own key.
  • Session keys are ed25519 keys. Their 64-byte signature over the raw text goes in signature as 0x hex, with the key itself (32 bytes, 0x hex) in agent.
jeets.trade
chain: <chainId>
account: 0x<40 lowercase hex digits>
nonce: <n>
action: open
market: BTC
side: long
margin: 10.000000 USDG
leverage: 1000x

The first four lines are the same for every action. The lines after them:

action: close
position: <position id>

action: withdraw
amount: 5.000000 USDG

action: set session key
session key: 0x<64 hex digits>
expires: 2026-10-13 04:20:00 UTC

action: set session key
session key: none

The expiry is UTC, with seconds; the last form revokes the session key.

POST /tx
{
  "tx": {
    "chain": "<chainId>",
    "signer": "0x…",
    "nonce": 3,
    "action": { "type": "open", "market": "BTC", "side": "long", "margin": 10000000, "leverage": 1000 }
  },
  "signature": "0x…",
  "agent": "<session key, 0x + 64 hex, only when it signed>"
}
  • Other actions: { "type": "close", "positionId": 12 }, { "type": "withdraw", "amount": 5000000 }, { "type": "setAgent", "agent": "0x…", "expiresAtMs": 1791866400000 } (a session key for at most 24 hours), and { "type": "setAgent", "agent": null, "expiresAtMs": 0 } to revoke it.
  • The response is { "hash": "0x…" }. The transaction’s result (or error) is at GET /tx/:hash once it has run, usually within half a second, and its Robinhood Chain block a second or two later.
  • A request refused up front comes back as HTTP 400 with { "error": "…" }, for example invalid wallet signature, stale nonce: next is 12, or a session key that’s expired or not authorized.
  • Session keys can sign only open and close.
  • A transaction signed for another chain id is refused without using up the nonce, so signatures can’t be replayed on a different Jeets chain.

JavaScript (viem)

import { privateKeyToAccount } from "viem/accounts";

const API = "https://api.jeets.trade";
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const signer = account.address.toLowerCase();

const { chainId } = await (await fetch(`${API}/markets`)).json();
const { nextNonce } = await (await fetch(`${API}/account/${signer}`)).json();

const text = [
  "jeets.trade",
  `chain: ${chainId}`,
  `account: ${signer}`,
  `nonce: ${nextNonce}`,
  "action: open",
  "market: BTC",
  "side: long",
  "margin: 10.000000 USDG",
  "leverage: 1000x",
].join("\n");

const signature = await account.signMessage({ message: text }); // personal_sign
const response = await fetch(`${API}/tx`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    tx: {
      chain: chainId,
      signer,
      nonce: nextNonce,
      action: { type: "open", market: "BTC", side: "long", margin: 10_000_000, leverage: 1000 },
    },
    signature,
  }),
});
console.log(await response.json()); // { hash: "0x…" }

Python (eth_account)

import os, requests
from eth_account import Account
from eth_account.messages import encode_defunct

API = "https://api.jeets.trade"
account = Account.from_key(os.environ["PRIVATE_KEY"])
signer = account.address.lower()

chain = requests.get(f"{API}/markets").json()["chainId"]
nonce = requests.get(f"{API}/account/{signer}").json()["nextNonce"]

text = "\n".join([
    "jeets.trade",
    f"chain: {chain}",
    f"account: {signer}",
    f"nonce: {nonce}",
    "action: withdraw",
    "amount: 5.000000 USDG",
])
signed = account.sign_message(encode_defunct(text=text))  # personal_sign
tx = {"chain": chain, "signer": signer, "nonce": nonce,
      "action": {"type": "withdraw", "amount": 5_000_000}}
print(requests.post(f"{API}/tx", json={"tx": tx, "signature": "0x" + bytes(signed.signature).hex()}).json())

Wallet

Deposit USDG

Withdraw