Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Try Testnet

This page talks to the live TxFlow testnet straight from your browser. It generates a throwaway key, claims testnet USDC, enables trading, and places real orders — every write is signed locally with the same EIP-712 + MessagePack flow described in Signing.

TESTNET · https://rpc.txflow-testnet.xyz
Latest block
…
Epoch
…
market
last
…
mark
…
oracle
…

Two examples

One terminal per instrument type — perpetuals and outcome. Each is the same three pieces: a ticker, a chart, and an order ticket. Only the outcome terminal differs in how it renders them: its price is a probability, so it plots a probability curve and its ticket picks YES or NO instead of buy or sell.

Both share one throwaway account. The button below runs the whole setup in one click:

StepEndpoint / actionReference
Generate a keyethers.Wallet.createRandom(), in your browserSigning
Claim USDCPOST /request-fund on the HTTP API host (see below) → credited to the perp accountKey Concepts
Enable tradingapproveAgent — the main key authorizes an agent key to sign ordersSigning
Fund the sub-accountstokenSend — perps and outcome each settle on their own sub-account, and the faucet only credits the perp onebelow

The faucet is rate-limited per address, so claim once and trade both.

Generates a throwaway key in your browser, claims testnet USDC, authorizes an agent key, and spreads the claim across the perp and outcome sub-accounts.
// every HTTP call sends the version header; /info replies are { success, code, data }
const API = 'https://rpc.txflow-testnet.xyz'
async function post(path: string, body: unknown) {
  const res = await fetch(API + path, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'x-api-version': '2026-08-16' },
    body: JSON.stringify(body),
  }).then((r) => r.json())
  return path === '/info' ? res.data : res
}
 
// move USDC between your own sub-accounts — "perp" | "outcome".
// Signed directly by the main key; an agent key cannot move funds.
const value = {
  txflowNetwork: 'TxFlow-Testnet',
  amount: '300',
  fromAccountType: 'perp',
  toAccountType: 'outcome',
  token: 'USDC:0xd04f0d19E8FbA49cfA541E272F9C60a2ad720464', // NAME:address, from the token list
  nonce: Date.now(),
}
const types = { TransferToken: [
  { name: 'txflowNetwork', type: 'string' }, { name: 'amount', type: 'string' },
  { name: 'fromAccountType', type: 'string' }, { name: 'toAccountType', type: 'string' },
  { name: 'token', type: 'string' }, { name: 'nonce', type: 'uint64' } ] }
const sig = ethers.Signature.from(await main.signTypedData(domain, types, value))
 
await post('/exchange', {
  action: { type: 'tokenSend', chainId: 2511, apiVersion: 1, toAddress: null, ...value },
  signature: { r: sig.r, s: sig.s, v: sig.v }, nonce: value.nonce, vaultAddress: null,
})

Setting toAddress sends to another user instead of between your own accounts; that variant signs the SendToken struct rather than TransferToken. The first send to a new address may charge a one-time 1 USDC activation fee (0 when the destination is yourself). See tokenSend.

Every terminal calls the same endpoints, changing only the instrument id:

PieceCall
Ticker/api-ws ticker subscription
Candles/info candleSnapshot for 90 days of history, /api-ws candle for today's open bar — on an outcome market the closes are probabilities, so the terminal draws them as a curve
Order bookl2Book — an outcome market passes its instrument_id as coin
Outcome card quotes/ws outcomeBbos, up to 50 instruments per subscription
Orderorder → POST /exchange, read back with frontendOpenOrders
CancelcancelByCloid → POST /exchange
// the only thing that differs between the three examples
const coin = String(instrumentId)   // 1 = BTC-USDC, 1284355 = an outcome market
 
// 90 daily candles; the open one keeps streaming on the `candle` channel
const history = await post('/info', {
  type: 'candleSnapshot',
  req: { coin, interval: '1d', startTime: Date.now() - 90 * 86_400_000, endTime: Date.now() },
})
 
ws.send(JSON.stringify({ method: 'subscribe', subscription: { type: 'ticker', coin, instrumentId } }))
ws.send(JSON.stringify({ method: 'subscribe', subscription: { type: 'candle', coin, interval: '1d' } }))
 
// order book — levels[0] is bids, levels[1] is asks, each best-first
const { levels } = await post('/info', { type: 'l2Book', coin })
 
// signOrder(agent, action) wraps the action in the signed envelope — see Signing.
// agent-signed order. `c` is a client order id — tag every order with one so
// you can cancel it by cloid.
await post('/exchange', await signOrder(agent, {
  type: 'order',
  grouping: 'na',
  orders: [{ a: instrumentId, b: true, p: '75000.0', s: '0.0006', r: false,
             t: { limit: { tif: 'Gtc' } }, c: 'my-order-001' }],
}))
 
await post('/exchange', await signOrder(agent, {
  type: 'cancelByCloid',
  cancels: [{ asset: instrumentId, cloid: 'my-order-001' }],
}))

Perpetuals

Perpetual instruments are named BASE-QUOTE and listed by perpMeta; the index field is the a you sign. Margin comes from the perp sub-account. See TIP 2: Perpetuals.

—no trades yet · price from the book
no candles yet
1d candles · candleSnapshot history, candle stream live
loading book…
l2Book · click to fill price
Create a test account above to sign orders.

Outcome

Outcome markets are prediction markets: two sides priced so that price(YES) + price(NO) = 1. They trade through the same order book and the same order action, keyed by instrumentId. See TIP 3: Outcome Markets.

Discovery is different: markets are grouped under events and scoped to a channel, so instead of perpMeta you list them with outcomeMeta. Testnet publishes them on channel 1.

That channel belongs to Probly, the first partner to run a channel on TxFlow. The questions in the terminal below, their tick sizes and settlement, and the resting orders you trade against are all Probly's — TxFlow provides the matching, margin, and settlement, the channel operator provides the markets and the liquidity. Anything you list with exchangeId: 1 is their venue; exchangeId: 0 is the default platform channel.

const { events } = await post('/info', { type: 'outcomeMeta', exchangeId: 1, limit: 50 })
const tradable = events
  .flatMap((e) => e.markets)
  .filter((m) => m.trading.accepting_orders && !m.trading.closed)
// → { instrument_id: 1284355, question: 'Will Hyperliquid perform an airdrop…',
//     instrument: { price_tick: '0.001', sz_decimals: 2 }, outcome_prices: ['0.295', '0.705'] }

Most of these have an active book but no fills yet, so ticker returns an empty lastPrice and candleSnapshot returns []. The terminal falls back to the book mid for the headline price.

There is one book per market and it is priced in YES, between 0 and 1 — that price is the market's probability. So the terminal below quotes both sides of it rather than a raw price:

In the terminalOn the wire
Buy YES at pb: true, p
Buy NO at qb: false, q
The NO bookthe same l2Book, mirrored: YES asks become NO bids at 1 − px
The chartthe close of each candleSnapshot bucket as a probability on a fixed 0–100% axis, not an OHLC candle
// buy 10 NO shares at 0.93
const yes = false
const price = '0.930'
await post('/exchange', await signOrder(agent, {
  type: 'order',
  grouping: 'na',
  orders: [{ a: instrumentId, b: yes, p: price, s: '10',
             r: false, t: { limit: { tif: 'Gtc' } }, c: 'my-outcome-001' }],
}))

Two more things differ. Margin comes from the outcome sub-account, funded by the tokenSend above. And the exchange can acknowledge an Outcome order asynchronously: if the queued order fails, /api-ws outcomeOrderUpdate pushes the reason under the returned traceId (successes are not pushed). Use /ws outcomeOrderUpdates for the matching lifecycle, and confirm the resting state with outcomeFrontendOpenOrders.

—YESno recent trades · price from the book
Markets and liquidity from Probly, the first partner channel on TxFlow — exchangeId: 1 on testnet.
100%50%0%no price yet
YES probability · 1d closes from candleSnapshot, candle stream live
loading book…
l2Book · YES prices · click to fill
Create a test account above to sign orders.

Testnet endpoints

Everything above talks to https://rpc.txflow-testnet.xyz: HTTP at /info and /exchange, WebSocket at wss://…/ws and wss://…/api-ws, and the faucet at POST /request-fund with { "address": "0x…" }. The domain values are under Networks.

To build your own client, start with the TypeScript SDK quickstart. For a direct protocol integration, use the Info API, WebSocket API, and Signing reference.