API reference · testnet
Exchange endpoint and signing
Every change to an account is a signed action sent to POST /exchange. The node checks the signature, runs the action in a block straight away and returns its result.
Request
{
"action": {
"type": "order",
"account": "0x5b1e…",
"market": 0,
"isBuy": true,
"price": 83300,
"size": 10,
"tif": "Ioc",
"reduceOnly": false
},
"nonce": 1791409090058,
"signature": "0x6c1d…1b",
"signatureChainId": null
}
| Field | Type | Description |
|---|---|---|
action | object | One of the actions below; type selects it |
nonce | u64 | Current time in ms (nonce rules) |
signature | hex string | 65 bytes: r ‖ s ‖ v, v = 27 or 28 (0 or 1 accepted). s must be in the lower half of the curve order (EIP-2) |
signatureChainId | u64 | Wallet-signed actions: required, the chain id the wallet signed on. Session-key actions: omit it (1337 is used) |
Signing
Actions are signed as EIP-712 typed data, which MetaMask, Rabby and other Ethereum wallets show in readable form. The digest is keccak256(0x1901 ‖ domainSeparator ‖ hashStruct(message)), with this domain:
{
"name": "Functor",
"version": "1",
"chainId": "<see below>",
"verifyingContract": "0x0000000000000000000000000000000000000000"
}
| Who signs | Actions | chainId |
|---|---|---|
| The wallet (owner of the account) | approveAgent, withdraw, usdClassTransfer, spotSend | The chain the wallet is on; send it as signatureChainId |
| A session key (agent) the wallet approved, or the wallet | order, cancel, setLeverage, spotOrder, spotCancel, vaultTransfer | 1337 |
Every typed struct ends with uint64 nonce. tif is signed as uint8: Gtc = 0, Ioc = 1, Alo = 2. The signer recovered from the signature must be the account field or a session key it approved; wallet-signed actions act on the signer's own account. A session key approved by one wallet trades only for that wallet, and can never withdraw or send funds. There is no action to revoke a session key yet: to retire one, stop using it and approve a new one.
Response
The action runs in a block immediately. The answer carries the block height and the result:
{
"status": "ok",
"response": {
"ticket": 4,
"height": 40539,
"result": {
"ticket": 4,
"ok": true,
"error": null,
"restingOid": null,
"filledLots": 10,
"avgPx": 83300,
"vaultUsd": null,
"vaultShares": null
}
}
}
| Field | Description |
|---|---|
status | ok if the action succeeded in its block, err if it failed or was refused |
result.error | Why it failed in the block (chain errors), else null |
result.restingOid | The order id if part of the order rests on the book |
result.filledLots | Lots filled on arrival (or in this block's auction) |
result.avgPx | Average fill price in ticks |
result.vaultUsd, result.vaultShares | Vault transfers: dollars moved and shares minted or burned |
A request refused before it reaches a block (bad signature, bad nonce, limit) answers 400 with {"status": "err", "response": "<reason>"} (list). approveAgent answers {"status": "ok", "response": {"ticket": n, "result": {"ok": true}}} with no height: it takes effect without a block.
Actions
approveAgent wallet-signed
Approve a session key (agent) to trade for this account. Takes effect at once. The agent can place and cancel orders, set leverage and move USDC between the account and a vault; it can never withdraw or send funds.
| Field | Type | Description |
|---|---|---|
agent | address | The session key's address. Not the signer itself, not a protocol account |
Signed as
ApproveAgent(address agent,uint64 nonce)Action
{
"type": "approveAgent",
"agent": "0x8f3c…"
}order session key or wallet
Place a perpetuals order. A buy fills against asks at or below price; what doesn't fill rests (GTC), is cancelled (IOC), or the whole order is refused if it would trade on arrival (ALO, post-only).
| Field | Type | Description |
|---|---|---|
account | address | The account trading |
market | u32 | Market id (0 BTC, 1 ETH, 2 SOL) |
isBuy | bool | |
price | u64 | Limit price in ticks (dollars ÷ tick) |
size | u64 | Size in lots (coins ÷ lot) |
tif | string | Gtc, Ioc or Alo. Signed as 0, 1, 2 |
reduceOnly | bool | Only reduces an existing position |
Signed as
Order(address account,uint32 market,bool isBuy,uint64 price,uint64 size,uint8 tif,bool reduceOnly,uint64 nonce)Action
{
"type": "order",
"account": "0x5b1e…",
"market": 0,
"isBuy": true,
"price": 83300,
"size": 10,
"tif": "Ioc",
"reduceOnly": false
}cancel session key or wallet
Cancel a resting perpetuals order.
| Field | Type | Description |
|---|---|---|
account | address | |
market | u32 | Market id |
orderId | u64 | restingOid from the order's result, or oid from openOrders |
Signed as
Cancel(address account,uint32 market,uint64 orderId,uint64 nonce)Action
{
"type": "cancel",
"account": "0x5b1e…",
"market": 0,
"orderId": 1954694
}setLeverage session key or wallet
Set the account's leverage on one market (cross margin). Without it, an account uses the market's maximum.
| Field | Type | Description |
|---|---|---|
account | address | |
market | u32 | Market id |
leverage | u32 | 1 to the market's maximum leverage |
Signed as
SetLeverage(address account,uint32 market,uint32 leverage,uint64 nonce)Action
{
"type": "setLeverage",
"account": "0x5b1e…",
"market": 0,
"leverage": 5
}withdraw wallet-signed
Withdraw USDC from the perpetuals account. On the testnet the USDC leaves the chain (there is no bridge yet). Allowed up to withdrawable: what is left after max(initial margin, 10% of position notional).
| Field | Type | Description |
|---|---|---|
amount | u64 | Micro-USDC (1 USDC = 1,000,000) |
Signed as
Withdraw(uint64 amount,uint64 nonce)Action
{
"type": "withdraw",
"amount": 100000000
}spotOrder session key or wallet
Place an FCTR/USDC order from the spot wallet. Bids are fully funded: the USDC is held while the order rests. During an auction phase only GTC orders are accepted and nothing trades until the auction ends.
| Field | Type | Description |
|---|---|---|
account | address | |
isBuy | bool | |
price | u64 | Ticks of $0.0001 per FCTR |
size | u64 | Lots of 0.01 FCTR (minimum 100 = 1 FCTR) |
tif | string | Gtc, Ioc or Alo (IOC and ALO only in continuous trading) |
Signed as
SpotOrder(address account,bool isBuy,uint64 price,uint64 size,uint8 tif,uint64 nonce)Action
{
"type": "spotOrder",
"account": "0x5b1e…",
"isBuy": true,
"price": 10000,
"size": 10000,
"tif": "Gtc"
}spotCancel session key or wallet
Cancel a resting FCTR/USDC order. Refused in the opening auction's closing window.
| Field | Type | Description |
|---|---|---|
account | address | |
orderId | u64 | Spot order id |
Signed as
SpotCancel(address account,uint64 orderId,uint64 nonce)Action
{
"type": "spotCancel",
"account": "0x5b1e…",
"orderId": 12
}usdClassTransfer wallet-signed
Move USDC between the perpetuals account and the spot wallet (Hyperliquid's usdClassTransfer). Perpetuals to spot is limited to withdrawable.
| Field | Type | Description |
|---|---|---|
amount | u64 | Micro-USDC |
toPerp | bool | true: spot → perpetuals; false: perpetuals → spot |
Signed as
UsdClassTransfer(uint64 amount,bool toPerp,uint64 nonce)Action
{
"type": "usdClassTransfer",
"amount": 50000000,
"toPerp": false
}spotSend wallet-signed
Send FCTR to another address. Locked (vesting) FCTR can't be sent; nothing can be sent to protocol accounts.
| Field | Type | Description |
|---|---|---|
destination | address | |
amount | u64 | FCTR base units (1 FCTR = 1,000,000,000) |
Signed as
SpotSend(address destination,uint64 amount,uint64 nonce)Action
{
"type": "spotSend",
"destination": "0x9a7d…",
"amount": 2000000000
}vaultTransfer session key or wallet
Deposit into or withdraw from an FLP vault. Money only moves between the account and the vault, so a session key may sign it. Withdrawals open 4 days after the account's last deposit into that vault; an amount above the account's value withdraws everything.
| Field | Type | Description |
|---|---|---|
account | address | |
vaultAddress | address | From vaults |
isDeposit | bool | |
usd | u64 | Micro-USDC |
Signed as
VaultTransfer(address account,address vaultAddress,bool isDeposit,uint64 usd,uint64 nonce)Action
{
"type": "vaultTransfer",
"account": "0x5b1e…",
"vaultAddress": "0xf1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1",
"isDeposit": true,
"usd": 100000000
}
Faucet (testnet)
POST /faucet with {"user": "0x…"} credits 10,000 mock USDC to the perpetuals account and, while the testnet faucet bucket lasts, 1,000 test FCTR to the spot wallet. No signature. Same response shape as /exchange; the ticket is the USDC credit. Limits: Rules.
Generated from the node's source code by tools/api-docs.mjs; examples are real responses from https://api.functorfund.com. Questions: Telegram. Changes: News.