REST API
There are two hosts:
| Host | What it serves |
|---|---|
https://v4-api.dev.parcllabs.com | Validator. Live state: markets, orderbooks, accounts by owner, oracle, staking, /v1/ws. |
https://v4-rest-api.dev.parcllabs.com | REST API. Auth (/auth/*), signing (/tx/sign-and-submit), bridge, account history, leaderboard, stats, explorer. |
The path tells you which host to hit. Each endpoint below is labeled.
All responses are JSON. Prices use 8 decimal places, sizes use 6, collateral (USDC) uses 6.
Field-naming convention
Most REST endpoints (markets, accounts, orderbook, oracle, staking) return camelCase field names — marketId, oraclePrice, lastFundingTimestamp.
Two surfaces use snake_case instead: GET /v1/markets/{id}/trades and every WebSocket event. Snake_case is used wherever the response shape mirrors an on-chain event (taker_order_id, tx_hash, taker_account_id). A client that deserializes both REST and WebSocket should expect either convention depending on the endpoint.
Markets
GET /v1/markets
Returns all markets.
curl https://v4-api.dev.parcllabs.com/v1/markets[
{
"marketId": 0,
"name": "NYC",
"assetClass": "RealEstate",
"status": "Active",
"oraclePrice": "58035000000",
"oracleStatus": "Active",
"oracleValidUntil": 1712433900,
"lastOraclePrice": "58035000000",
"lastOracleTimestamp": 1712345678000,
"markPrice": "58177000000",
"bestBid": "58100000000",
"bestAsk": "58200000000",
"openInterestLong": "37460000",
"openInterestShort": "37460000",
"maxOpenInterest": "1000000000",
"fundingRate": "-15800",
"lastFundingTimestamp": 1712345678,
"fundingIntervalSecs": 3600,
"interestRateMicroBps": 64,
"makerFeeBps": 0,
"takerFeeBps": 0,
"initialMarginRatioBps": 200,
"maintenanceMarginRatioBps": 100,
"priceBandBps": 1000,
"tickSize": "1000000"
}
]assetClass is RealEstate or Commodities. Real-estate markets have initialMarginRatioBps: 200 (50x leverage cap) and maintenanceMarginRatioBps: 100. Commodity markets have 500 and 250 respectively (20x cap). priceBandBps is the per-update oracle sanity cap. Commodity markets also carry a tradingHours object describing the underlying venue's session schedule.
GET /v1/markets/{id}
Returns a single market by ID, with the same shape as one element of GET /v1/markets.
GET /v1/markets/{id}/orderbook
{
"marketId": 0,
"bids": [
{ "price": "58100000000", "size": "500000", "orderCount": 1 },
{ "price": "58050000000", "size": "1200000", "orderCount": 3 }
],
"asks": [
{ "price": "58200000000", "size": "300000", "orderCount": 1 },
{ "price": "58250000000", "size": "800000", "orderCount": 2 }
]
}GET /v1/markets/{id}/funding
Returns the current funding state for a market.
{
"marketId": 0,
"fundingRate": "69183",
"lastFundingTimestamp": 1779819896651,
"fundingIntervalSecs": 3600,
"cumulativeFunding": "2388785636613712714",
"maxFundingRateBps": 625
}fundingRate is the running estimate that will settle on the next hourly crank; see Funding for the rate-computation details. cumulativeFunding is the per-market index that each position settles against.
GET /v1/markets/{id}/trades
Returns recent trades. Response is an array; each element uses snake_case fields (maker_order_id, taker_order_id, tx_hash) to match the WebSocket fill event shape — see Field-naming convention.
Accounts
GET /v1/accounts/{id}
{
"accountId": 12,
"owner": "0x35504e68...",
"mode": "Cross",
"collateral": "21929491932",
"positions": [
{
"marketId": 0,
"side": "Long",
"size": "64560188",
"entryPrice": "58211606845",
"unrealizedPnl": "-120297107",
"cumulativeFunding": "0",
"lastOraclePrice": "58090000000",
"openedAt": 1712345678000
}
],
"openOrders": [],
"createdAt": 1712300000000,
"volume30d": 37581522814
}GET /v1/accounts/by-owner/{pubkey}
Same response as above. Looks up by the owner's public key. Accepts both 0x-prefixed and bare hex (e.g. 0x35504e68... or 35504e68...).
GET /v1/accounts/{id}/positions
Returns just the positions array.
GET /v1/accounts/{id}/orders
Returns just the open orders array.
Oracle
GET /v1/oracle/{market_id}
Current oracle state for a market.
{
"marketId": 0,
"price": "58035000000",
"lastUpdateDate": 20260406,
"lastUpdateTimestamp": 1712345678000,
"validUntil": 1712433900,
"status": "Active"
}GET /v1/oracle/{market_id}/history
Returns the historical oracle prices for a market.
{
"marketId": 0,
"prices": [
{ "time": 1748217600, "price": "59738000000" },
{ "time": 1748304000, "price": "59855999999" }
]
}time is Unix seconds. price is the oracle value at that point, scaled to PRICE_EXPO = -8. Real-estate markets emit one point per day; commodity markets emit higher-frequency points.
Exchange
GET /v1/node/info
{
"protocol_version": 3,
"binary_version": 3,
"build_tag": "dev",
"block_height": 73000,
"block_timestamp": 1712345678943,
"state_root": "0x4d419b60..."
}state_root is 0x-prefixed hex (32 bytes).
Transactions
POST /tx/sign-and-submit
Host: v4-rest-api.dev.parcllabs.com.
Submit a transaction body and have the server sign (via enclave) and forward it to the validator. Requires an API key (X-API-Key header). API keys are scoped to trade-only, see authentication for the allowlist.
Request body:
{
"transaction": {
"PlaceOrder": {
"account_id": 12,
"market_id": 0,
"side": "Long",
"order_type": "Market",
"price": 0,
"size": 100000,
"trigger_price": null,
"reduce_only": false,
"post_only": false,
"time_in_force": "IOC"
}
},
"nonce": 1713456789000,
"timestamp": 1713456789
}Response on success:
{
"status": "success",
"hash": "0x9dd57899...",
"events": [
{ "type": "Fill", "market_id": 0, "price": "58100000000", "size": "100000", ... }
]
}Response on failure:
{
"status": "failed",
"hash": "0x9dd57899...",
"events": [],
"error": "insufficient margin"
}events is always present (empty on failure). It contains all state changes caused by the transaction — fills, order placements, cancellations, liquidations, etc.
Staking
GET /v1/staking/validators
Returns all registered validators with stake, commission, uptime, and status.
GET /v1/staking/validators/{pubkey}
Returns a single validator by public key.
GET /v1/staking/info
Returns network staking stats: total staked, active validators, epoch info, APY.
GET /v1/staking/balance/{pubkey}
Returns the PRCL staking balance for a public key.
GET /v1/staking/delegations/{pubkey}
Returns all delegations by a public key.
GET /v1/staking/unstakes/{pubkey}
Returns pending unstakes for a public key.
Leaderboard
GET /v1/leaderboard
Public. Returns the competition leaderboard sorted by PnL, along with competition metadata.
{
"competition": {
"name": "Devnet Season 1",
"startTime": 1713398400000,
"endTime": 1714608000000,
"prizePool": "1000000000"
},
"leaderboard": [
{
"rank": 1,
"accountId": 12,
"owner": "0x35504e68...",
"pnl": 4821000000,
"roi": 0.4821,
"accountValue": 14821000000,
"volume": 98532000000,
"tradeCount": 142
}
]
}pnl, accountValue, and volume are in USDC with 6 decimal places. roi is a decimal fraction (0.48 = 48%).
If no competition is configured, competition is null.
Statistics
GET /v1/stats
Host: v4-rest-api.dev.parcllabs.com. Public. Returns aggregated exchange statistics.
{
"totalVolume": "1234567890000",
"volume24h": "98765432100",
"totalTrades": 4821,
"trades24h": 312,
"totalAccounts": 87,
"totalLiquidations": 3,
"liquidations24h": 0,
"totalBankruptcies": 1,
"bankruptcies24h": 0,
"totalLiquidationFees": "50000000",
"totalDeposits": "8700000000000",
"totalWithdrawals": "120000000000"
}All monetary values are in USDC with 6 decimal places.
Account history
Host: v4-rest-api.dev.parcllabs.com.
These endpoints require authentication (JWT in the Authorization: Bearer header, or X-API-Key for bots). They return data only for accounts you own.
GET /v1/accounts/{id}/trades
Returns fill history for your account.
Query params:
limit— max results, up to 500 (default 100)offset— pagination offsetstartTime— Unix timestamp ms (inclusive)endTime— Unix timestamp ms (exclusive)marketId— filter to one market
[
{
"timestamp": 1713456789000,
"marketId": 0,
"side": "Long",
"size": "100000",
"price": "58150000000",
"fee": "0",
"role": "taker",
"orderId": 42,
"txHash": "9dd57899..."
}
]GET /v1/accounts/{id}/trades/csv
Same as above but returns a CSV file. Useful for tax/accounting exports. Accepts the same query params (no limit — returns all matching records).
GET /v1/accounts/{id}/orders
Returns order history with fill status.
Query params:
limit— max results, up to 200 (default 50)offset,startTime,endTime,marketId— same as tradesstatus— filter by status:open,filled,canceled,partially_filled,all(defaultall)
[
{
"orderId": 42,
"timestamp": 1713456789000,
"marketId": 0,
"side": "Long",
"price": "58000000000",
"size": "100000",
"filledSize": "100000",
"avgFillPrice": "58150000000",
"status": "filled",
"cancelReason": null
}
]GET /v1/accounts/{id}/funding
Returns funding payment history.
Query params: limit, offset, startTime, endTime, marketId
[
{
"timestamp": 1713456000000,
"marketId": 0,
"side": "Long",
"positionSize": "500000",
"fundingRate": "-8750000",
"payment": "-12500",
"cumulativeFunding": "-12500"
}
]payment is in USDC lamports (6 decimals). Negative means you paid; positive means you received.