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

REST API

There are two hosts:

HostWhat it serves
https://v4-api.dev.parcllabs.comValidator. Live state: markets, orderbooks, accounts by owner, oracle, staking, /v1/ws.
https://v4-rest-api.dev.parcllabs.comREST 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 offset
  • startTime — 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 trades
  • status — filter by status: open, filled, canceled, partially_filled, all (default all)
[
  {
    "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.