Pascal Exchange API

Pascal Exchange API#

Public reference for integrating Pascal's exchange REST and WebSocket API for trading.

For request signing, see signing.md. Most integrators should use the Pascal client SDKs when available; the raw protocol is documented here for SDK authors, market makers, and direct integrations.

Base URLs#

CanaryStaging
Webhttps://canary.pascal.tradehttps://staging.pascal.trade
Write APIhttps://trade.canary.pascal.tradehttps://trade.staging.pascal.trade
REST Read APIhttps://data.canary.pascal.tradehttps://data.staging.pascal.trade
WebSocketwss://data.canary.pascal.trade/wswss://data.staging.pascal.trade/ws

All /api/v1/... examples use the canary hosts.

Authentication#

Pascal separates account ownership from trading authorization.

KeyUseUsed by
Wallet keyCustody, withdrawals, and trading-key lifecycleCreate/revoke trading keys, withdraw collateral, register deposit addresses
Trading keyOrder placement and cancellationPlace and cancel orders

In every signed request, owner is the wallet public key and signer is the key that produced the Ed25519 signature. Wallet-signed requests require signer == owner.

Replay Protection#

Every signed request carries replay and staleness protection fields client_ts_ms and recv_window_ms:

Signature Object

FieldTypeRequiredDescription
client_ts_msinteger stringYesClient ts ms.
recv_window_msinteger stringYesRecv window ms.
deployment_idinteger stringYesDeployment id.
ownerbase58 stringYesOwner.
signerbase58 stringYesSigner.
signaturebase58 stringYesSignature.

Response Envelopes#

Read API success responses use status: "success", endpoint-specific data, and round context. Validation and lookup failures use status: "error" with data.code and optional data.details.

Write API responses use one envelope per command. Batch endpoints return an array of write envelopes; single-command endpoints return one write envelope.

Examples
json
{
  "status": "success",
  "data": {
    "server_time_ms": "1731536000050"
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}
json
{
  "status": "error",
  "data": {
    "code": "invalid_request",
    "details": {
      "reason": "count_back must be positive"
    }
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}
json
[
  {
    "status": "success",
    "data": {
      "type": "place_order",
      "order": {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "side": "BID",
        "size_original": "10",
        "size_filled": "3",
        "notional_filled": "1.650000",
        "size_remaining": "7",
        "price": "0.550000",
        "status": "OPEN",
        "tif": "GTC",
        "type": "LIMIT",
        "post_only": false,
        "reduce_only": false,
        "expires_ts_ms": "0",
        "client_order_id": "42",
        "id": "987654321",
        "place_ts_ms": "1731536000050",
        "place_round": "12345",
        "update_ts_ms": "1731536000050",
        "update_round": "12345"
      },
      "fills": [
        {
          "symbol": "SIM_EVENT_1.MARKET_1",
          "client_order_id": "42",
          "order_id": "987654321",
          "trade_id": "555001",
          "trade_ts_ms": "1731536000050",
          "cursor": "00000000000000067891:0000000000",
          "round": "12345",
          "side": "BID",
          "liquidity": "TAKER",
          "fill_size": "3",
          "fill_price": "0.550000",
          "fee_usd": "-0.020000",
          "collateral_change_usd": "-1.650000",
          "position_size_prev": "0",
          "realized_pnl_usd": "0.000000"
        }
      ]
    },
    "correlation_id": "170000000000000123",
    "round": "12345",
    "exchange_time_ms": "1731536000050"
  }
]
json
{
  "status": "error",
  "data": {
    "code": "duplicate_client_order_id",
    "details": "client_order_id 42 is already open"
  },
  "correlation_id": "170000000000000123",
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

JSON Conventions#

ShapeEncoding
Decimal prices, USD amounts, rates, and feesString with 6 decimal places unless the field description says otherwise.
Contract sizes, sequence numbers, ids, timestamps, and cursorsString when the value can exceed JavaScript's safe integer range.
TimestampsUnix milliseconds.
Public keys and Ed25519 signaturesBase58 strings.
Market symbolsUppercase string identifiers.

Trading Endpoints#

All write endpoints accept a tagged WriteRequest body. The current HTTP router uses a shared handler, but clients should send each request variant to the path documented here.

Place And Replace Orders#

POST <write_base_url>/api/v1/order

Places or amends one or more orders. Each order is independently signed and independently succeeds or fails. The maximum batch size is 50.

Examples
bash
curl -X POST https://trade.canary.pascal.trade/api/v1/order \
  -H 'Content-Type: application/json' \
  --data @- <<'EOF'
{
  "type": "batch_place",
  "orders": [
    {
      "symbol": "SIM_EVENT_1.MARKET_1",
      "side": "BID",
      "size": "10",
      "price": "0.550000",
      "tif": "GTC",
      "type": "LIMIT",
      "post_only": false,
      "reduce_only": false,
      "expires_ts_ms": "0",
      "client_order_id": "42",
      "metadata": "0",
      "signature": {
        "client_ts_ms": "1731536000000",
        "recv_window_ms": "5000",
        "deployment_id": "2",
        "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
        "signer": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1",
        "signature": "FVmKzV22fyPA1sjJ7uTVBxLYXyGSNZN299PWGMGBNCqPd9gikZsetPTC4snfCG223fWGpbT9T7vBeLdUVUCm6wi"
      }
    }
  ]
}
EOF
json
[
  {
    "status": "success",
    "data": {
      "type": "place_order",
      "order": {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "side": "BID",
        "size_original": "10",
        "size_filled": "3",
        "notional_filled": "1.650000",
        "size_remaining": "7",
        "price": "0.550000",
        "status": "OPEN",
        "tif": "GTC",
        "type": "LIMIT",
        "post_only": false,
        "reduce_only": false,
        "expires_ts_ms": "0",
        "client_order_id": "42",
        "id": "987654321",
        "place_ts_ms": "1731536000050",
        "place_round": "12345",
        "update_ts_ms": "1731536000050",
        "update_round": "12345"
      },
      "fills": [
        {
          "symbol": "SIM_EVENT_1.MARKET_1",
          "client_order_id": "42",
          "order_id": "987654321",
          "trade_id": "555001",
          "trade_ts_ms": "1731536000050",
          "cursor": "00000000000000067891:0000000000",
          "round": "12345",
          "side": "BID",
          "liquidity": "TAKER",
          "fill_size": "3",
          "fill_price": "0.550000",
          "fee_usd": "-0.020000",
          "collateral_change_usd": "-1.650000",
          "position_size_prev": "0",
          "realized_pnl_usd": "0.000000"
        }
      ]
    },
    "correlation_id": "170000000000000123",
    "round": "12345",
    "exchange_time_ms": "1731536000050"
  }
]

JSON Response Payload

Batch responses are JSON arrays of write envelopes. On success, each envelope's data object has type: "place_order" and these fields:

FieldTypeRequiredDescription
orderOrderMsgYesOrder.
fillsarray of FillMsgYesFills.

order object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
sideSideYesSide.
size_originalinteger stringYesSize original.
size_filledinteger stringYesSize filled.
notional_filleddecimal string, 6 d.p.YesCumulative notional fill value: sum of fill_price * fill_size for all fills. Divide by size_filled to get the average fill price.
size_remaininginteger stringYesSize remaining.
pricedecimal string, 6 d.p.YesPrice.
statusOrderStatusYesStatus.
tifTimeInForceYesTif.
typeOrderTypeYesType.
post_onlybooleanYesPost only.
reduce_onlybooleanYesReduce only.
expires_ts_msinteger stringYesExpires ts ms.
client_order_idinteger stringYesClient order id.
idinteger stringYesId.
place_ts_msinteger stringYesPlace ts ms.
place_roundinteger stringYesPlace round.
update_ts_msinteger stringYesUpdate ts ms.
update_roundinteger stringYesUpdate round.
builder_keybase58 stringNoBuilder key.
builder_fee_ratesigned decimal string, 6 d.p.NoBuilder fee rate.

Every element in fills is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
client_order_idinteger stringYesClient order id.
order_idinteger stringYesOrder id.
trade_idinteger stringYesTrade id.
trade_ts_msinteger stringYesTrade ts ms.
cursorfixed-width cursor stringYesCursor.
roundinteger stringYesRound.
sideSideYesSide.
liquidityLiquidityYesLiquidity.
fill_sizeinteger stringYesFill size.
fill_pricedecimal string, 6 d.p.YesFill price.
fee_usdsigned decimal string, 6 d.p.YesFee usd.
collateral_change_usdsigned decimal string, 6 d.p.YesCollateral change usd.
builder_keybase58 stringNoBuilder key.
builder_fee_usdsigned decimal string, 6 d.p.NoBuilder fee usd.
position_size_prevsigned integer stringYesPosition size prev.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized pnl usd.

Request Body

FieldTypeRequiredDescription
typestring literal "batch_place"YesRequest discriminator.
ordersarray of PlaceOrderRequestYesOrders to submit in this batch.

Every element in orders is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol for the contract to trade.
sideSideYesWhether to buy (BID) or sell (ASK).
sizeinteger stringYesOrder size in contracts.
pricedecimal string, 6 d.p.YesLimit price.
tifTimeInForceYesTime-in-force policy. MARKET orders must use IOC.
typeOrderTypeYesDisplay order type. MARKET is accepted only with IOC and otherwise behaves like an IOC limit order.
post_onlybooleanNoIf true, reject the order instead of resting it when it would cross immediately.
reduce_onlybooleanNoIf true, only reduce existing exposure and never increase it.
expires_ts_msinteger stringNoExpiration timestamp required for GTT orders and zero otherwise.
client_order_idinteger stringYesClient-assigned order identifier, unique per account.
replace_client_order_idinteger stringNoExisting client order identifier to replace atomically, if any.
builder_infoBuilderInfoNoOptional builder attribution and fee settings.
metadatainteger stringYesOpaque metadata byte included in the signed payload.
signatureRequestSignatureYesRequest signature and replay-protection metadata.

Cancel Orders#

POST <write_base_url>/api/v1/order

Cancels one or more orders by client order id or exchange order id. Each cancel is independently signed and independently succeeds or fails. The maximum batch size is 50.

Examples
bash
curl -X POST https://trade.canary.pascal.trade/api/v1/order \
  -H 'Content-Type: application/json' \
  --data @- <<'EOF'
{
  "type": "batch_cancel",
  "cancels": [
    {
      "signature": {
        "client_ts_ms": "1731536000000",
        "recv_window_ms": "5000",
        "deployment_id": "2",
        "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
        "signer": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1",
        "signature": "64uzbMXBYz6yAJRUnZZxyHYQSri4FqYaVvCF7TPbve38PGQw9grY7ohNT25MPqumkVCrPjVLdkXthZHAV7Rbjp6T"
      },
      "client_order_id": "42",
      "metadata": "1"
    }
  ]
}
EOF
json
[
  {
    "status": "success",
    "data": {
      "type": "cancel_order",
      "order": {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "side": "BID",
        "size_original": "10",
        "size_filled": "3",
        "notional_filled": "1.650000",
        "size_remaining": "7",
        "price": "0.550000",
        "status": "OPEN",
        "tif": "GTC",
        "type": "LIMIT",
        "post_only": false,
        "reduce_only": false,
        "expires_ts_ms": "0",
        "client_order_id": "42",
        "id": "987654321",
        "place_ts_ms": "1731536000050",
        "place_round": "12345",
        "update_ts_ms": "1731536000050",
        "update_round": "12345"
      }
    },
    "correlation_id": "170000000000000123",
    "round": "12345",
    "exchange_time_ms": "1731536000050"
  }
]

JSON Response Payload

Batch responses are JSON arrays of write envelopes. On success, each envelope's data object has type: "cancel_order" and these fields:

FieldTypeRequiredDescription
typestring literal "cancel_order"YesRequest discriminator.
orderOrderMsgYesOrder.

order object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
sideSideYesSide.
size_originalinteger stringYesSize original.
size_filledinteger stringYesSize filled.
notional_filleddecimal string, 6 d.p.YesCumulative notional fill value: sum of fill_price * fill_size for all fills. Divide by size_filled to get the average fill price.
size_remaininginteger stringYesSize remaining.
pricedecimal string, 6 d.p.YesPrice.
statusOrderStatusYesStatus.
tifTimeInForceYesTif.
typeOrderTypeYesType.
post_onlybooleanYesPost only.
reduce_onlybooleanYesReduce only.
expires_ts_msinteger stringYesExpires ts ms.
client_order_idinteger stringYesClient order id.
idinteger stringYesId.
place_ts_msinteger stringYesPlace ts ms.
place_roundinteger stringYesPlace round.
update_ts_msinteger stringYesUpdate ts ms.
update_roundinteger stringYesUpdate round.
builder_keybase58 stringNoBuilder key.
builder_fee_ratesigned decimal string, 6 d.p.NoBuilder fee rate.

Request Body

FieldTypeRequiredDescription
typestring literal "batch_cancel"YesRequest discriminator.
cancelsarray of CancelOrderRequestYesCancel requests to submit in this batch.

Every element in cancels is a JSON object:

FieldTypeRequiredDescription
signatureRequestSignatureYesSignature.
client_order_idinteger stringOne ofClient order id.
order_idinteger stringOne ofOrder id.
metadatainteger stringYesMetadata.

Create A Trading Key#

POST <write_base_url>/api/v1/api-key

Authorizes a trading key for an account. This request is wallet-signed.

Examples
bash
curl -X POST https://trade.canary.pascal.trade/api/v1/api-key \
  -H 'Content-Type: application/json' \
  --data @- <<'EOF'
{
  "type": "create_trading_key",
  "key": {
    "signature": {
      "client_ts_ms": "1731536000000",
      "recv_window_ms": "5000",
      "deployment_id": "2",
      "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signature": "27ZXesvQMpSKiQDMTZQ9XXyy1Wvv853TPzVVQKxHV6dcZhgjhzzncbes3FmCrRJMFwHc3b84JnK87pNHvUUz8NQT"
    },
    "trading_key": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1",
    "name": "api-doc-key",
    "expiration_ts_ms": "1732140800000"
  }
}
EOF
json
{
  "status": "success",
  "data": {
    "type": "create_trading_key",
    "trading_key": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1",
    "name": "api-doc-key",
    "expiration_ts_ms": "1732140800000"
  },
  "correlation_id": "170000000000000123",
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

JSON Response Payload

On success, the response envelope's data object has type: "create_trading_key" and these fields:

FieldTypeRequiredDescription
trading_keybase58 stringYesTrading key.
namestringYesName.
expiration_ts_msinteger stringYesExpiration ts ms.

Request Body

FieldTypeRequiredDescription
typestring literal "create_trading_key"YesRequest discriminator.
keyCreateTradingKeyRequestYesTrading key creation payload.
FieldTypeRequiredDescription
signatureRequestSignatureYesSignature.
trading_keybase58 stringYesTrading key.
namestringYesName.
expiration_ts_msinteger stringYesExpiration ts ms.

Revoke A Trading Key#

POST <write_base_url>/api/v1/api-key

Revokes a previously authorized trading key. This request is wallet-signed.

Examples
bash
curl -X POST https://trade.canary.pascal.trade/api/v1/api-key \
  -H 'Content-Type: application/json' \
  --data @- <<'EOF'
{
  "type": "revoke_trading_key",
  "key": {
    "signature": {
      "client_ts_ms": "1731536000000",
      "recv_window_ms": "5000",
      "deployment_id": "2",
      "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signature": "uApf45JWVGXK4D95WJcWEc4rkC5mP6BbsG43t7H7eXYrvUiHiwQVSCB3KgB3ygRZJgM5o313xhyHk9mWXEHdJz1"
    },
    "trading_key": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1"
  }
}
EOF
json
{
  "status": "success",
  "data": {
    "type": "revoke_trading_key",
    "trading_key": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1"
  },
  "correlation_id": "170000000000000123",
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

JSON Response Payload

On success, the response envelope's data object has type: "revoke_trading_key" and these fields:

FieldTypeRequiredDescription
typestring literal "revoke_trading_key"YesRequest discriminator.
trading_keybase58 stringYesTrading key.

Request Body

FieldTypeRequiredDescription
typestring literal "revoke_trading_key"YesRequest discriminator.
keyRevokeTradingKeyRequestYesTrading key revocation payload.
FieldTypeRequiredDescription
signatureRequestSignatureYesSignature.
trading_keybase58 stringYesTrading key.

Withdraw Collateral#

POST <write_base_url>/api/v1/withdraw

Requests withdrawal of collateral to a destination token account. This request is wallet-signed.

Examples
bash
curl -X POST https://trade.canary.pascal.trade/api/v1/withdraw \
  -H 'Content-Type: application/json' \
  --data @- <<'EOF'
{
  "type": "withdraw",
  "withdraw": {
    "signature": {
      "client_ts_ms": "1731536000000",
      "recv_window_ms": "5000",
      "deployment_id": "2",
      "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signature": "3AdcFDayePHf2G2F9jzAE8Xp7nC2MNVanHYn5Vg44pKmuT32Aj8YffaNT8qRpTDiJwqEheBy7Lvdinr9cbW9xA7m"
    },
    "amount": "25.000000",
    "destination_authority": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
    "destination_token_account": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB"
  }
}
EOF
json
{
  "status": "success",
  "data": {
    "type": "withdrawal",
    "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
    "amount": "25.000000",
    "destination_authority": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
    "destination_token_account": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB"
  },
  "correlation_id": "170000000000000123",
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

JSON Response Payload

On success, the response envelope's data object has type: "withdrawal" and these fields:

FieldTypeRequiredDescription
typestring literal "withdrawal"YesRequest discriminator.
ownerbase58 stringYesOwner.
amountdecimal string, 6 d.p.YesAmount.
destination_authoritybase58 stringYesDestination authority.
destination_token_accountbase58 stringYesDestination token account.

Request Body

FieldTypeRequiredDescription
typestring literal "withdraw"YesRequest discriminator.
withdrawWithdrawRequestYesWithdrawal payload.
FieldTypeRequiredDescription
signatureRequestSignatureYesSignature.
amountdecimal string, 6 d.p.YesAmount.
destination_authoritybase58 stringYesDestination authority.
destination_token_accountbase58 stringYesDestination token account.

Register A Deposit Address#

POST <write_base_url>/api/v1/deposit-address

Registers the owner's deposit address for balance scanning. This request is wallet-signed.

Examples
bash
curl -X POST https://trade.canary.pascal.trade/api/v1/deposit-address \
  -H 'Content-Type: application/json' \
  --data @- <<'EOF'
{
  "type": "register_deposit_address",
  "registration": {
    "signature": {
      "client_ts_ms": "1731536000000",
      "recv_window_ms": "5000",
      "deployment_id": "2",
      "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signer": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "signature": "SmycN1kHAggVjooQvGSKCkqUMtk17h5ZZZudtoqBVGvjQyZxEutXTHVG7bZEYurfT4jmrBc7wFFW6pL9yvJbyMc"
    },
    "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB"
  }
}
EOF
json
{
  "status": "success",
  "data": {
    "type": "empty"
  },
  "correlation_id": "170000000000000123",
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

JSON Response Payload

On success, the response envelope's data object has type: "empty" and no additional fields.

Request Body

FieldTypeRequiredDescription
typestring literal "register_deposit_address"YesRequest discriminator.
registrationRegisterDepositAddressRequestYesDeposit address registration payload.
FieldTypeRequiredDescription
signatureRequestSignatureYesSignature.
ownerbase58 stringYesOwner.

Market Data Endpoints#

Server Time#

GET <read_base_url>/api/v1/time

Returns the read API server's current wall-clock time in milliseconds.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/time'
json
{
  "status": "success",
  "data": {
    "server_time_ms": "1731536000050"
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

JSON Response Payload

FieldTypeRequiredDescription
server_time_msinteger stringYesServer time ms.

ESM Version#

GET <read_base_url>/api/v1/esm-version

Returns the active ESM protocol version replicated by the read API.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/esm-version'
json
{
  "status": "success",
  "data": {
    "esm_version": 2
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

JSON Response Payload

FieldTypeRequiredDescription
esm_versionintegerYesEsm version.

Markets#

GET <read_base_url>/api/v1/markets

Returns listed markets and their current derived state.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/markets?strict=true'
json
{
  "status": "success",
  "data": [
    {
      "symbol": "SIM_EVENT_1.MARKET_1",
      "taker_fee_rate": "0.001000",
      "maker_rebate_share": "0.500000",
      "tick_size_min": "0.010000",
      "tick_sig_figs": 2,
      "event_description": "API documentation sample market",
      "expected_resolution_time_ms": "1735000000000",
      "market_description": "Yes",
      "reverse_description": "No",
      "sort_order": "SymbolAsc",
      "tags": [
        "docs"
      ],
      "topic": {
        "id": "docs",
        "description": "Documentation examples"
      },
      "mark_price": "0.550000",
      "open_interest": "250",
      "resolution": null,
      "mark_price_24h_baseline": "0.520000",
      "market_stats_by_window": {},
      "market_stats_all_time": null
    }
  ],
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
strictbooleanNoIf true, only return markets whose [MarketDisplayAttributes] parse successfully on the current version.

JSON Response Payload

Returns a JSON array of market objects. Every element in the array is a JSON object:

FieldTypeRequiredDescription
symbolstringYesHuman-readable identifier for a market. Globally Unique. See ontology.md for details Eg "NYCMAYOR_20251104.MAMDANI" The markets event is derived from it's symbol see [Symbol::event_code()]
taker_fee_ratesigned decimal string, 6 d.p.YesBase fee rate paid by takers. Decimal string, e.g. "0.0010" for 10 bps. See [pascal_types::math::taker_fee] for more details.
maker_rebate_sharesigned decimal string, 6 d.p.YesShare of taker fee rebated to makers. Decimal string, e.g. "0.50" for 50%. See [pascal_types::math::fee_share] for more details.
tick_size_mindecimal string, 6 d.p.YesMinimum tick size. The tick size for a given price px is: max(tick_size_min, 10^(floor(log10(px')) - tick_sig_figs + 1)) where px' = min(px, 1 - px) The intuition is that we want some amount of decimal precision available, but we don't want to count 0 prefixes. For example, 0.0025, 0.025 and 0.25 all have 2 digits of precision.
tick_sig_figsintegerYesNumber of significant figures in the tick size formula. Must be in [1, 6].
display_attributes.*object mapping string to JSON valueYesFlattened display-only metadata fields.
mark_pricedecimal string, 6 d.p.NoMedian of whichever of (best bid, best ask, last trade) are available. Defaults to 50 cents if no mark price exists yet.
open_interestinteger stringYesCurrent open interest.
resolutionMarketResolutionMsgNoFinal market resolution, if this market has resolved.
mark_price_24h_baselinedecimal string, 6 d.p.NoMark price baseline used to calculate 24h mark price change. None means no 24h baseline mark price is available.
market_stats_by_windowobject mapping MarketStatsWindowKey to MarketStatsSnapshotMsgNoRolling market statistics snapshots for this market. Keys are window durations in milliseconds encoded as JSON object keys (string form). For example, "86400000" is the 1-day window. Empty means no stats are available for this market yet (for example, newly listed markets).
market_stats_all_timeMarketStatsSnapshotMsgNoAll-time cumulative market statistics snapshot for this market. None means no all-time stats are available for this market yet.

resolution object:

FieldTypeRequiredDescription
pricedecimal string, 6 d.p.YesPrice.
time_msinteger stringYesTime ms.
roundinteger stringYesRound.

Each market_stats_by_window value and market_stats_all_time object:

FieldTypeRequiredDescription
taker_buy_volumeinteger stringYesTotal base-asset volume bought by takers in the window.
taker_sell_volumeinteger stringYesTotal base-asset volume sold by takers in the window.
taker_buy_volume_notionaldecimal string, 6 d.p.YesTotal quote-notional bought by takers in the window.
taker_sell_volume_notionaldecimal string, 6 d.p.YesTotal quote-notional sold by takers in the window.
taker_buy_trade_countinteger stringYesTotal number of buy-side taker trades included in the snapshot window.
taker_sell_trade_countinteger stringYesTotal number of sell-side taker trades included in the snapshot window.
end_ms_exclusiveinteger stringYesExclusive upper-bound timestamp for the aggregation window.
as_of_roundinteger stringYesSequencer round watermark used when this snapshot was computed. Trades from rounds greater than as_of_round are excluded.
as_of_exchange_time_msinteger stringYesAs-of watermark exchange time at query time.

Order Book#

GET <read_base_url>/api/v1/book

Returns the current order book for one market.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/book?symbol=SIM_EVENT_1.MARKET_1'
json
{
  "status": "success",
  "data": {
    "asks": [
      [
        "0.560000",
        "12"
      ],
      [
        "0.570000",
        "20"
      ]
    ],
    "bids": [
      [
        "0.540000",
        "15"
      ],
      [
        "0.530000",
        "7"
      ]
    ],
    "spec": {
      "symbol": "SIM_EVENT_1.MARKET_1",
      "taker_fee_rate": "0.001000",
      "maker_rebate_share": "0.500000",
      "tick_size_min": "0.010000",
      "tick_sig_figs": 2
    }
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
symbolstringYesSymbol.

JSON Response Payload

FieldTypeRequiredDescription
asksarray of tuple (decimal string, 6 d.p., integer string)YesAsks.
bidsarray of tuple (decimal string, 6 d.p., integer string)YesBids.
specMarketSpecNoSpec.

spec object:

FieldTypeRequiredDescription
symbolstringYesHuman-readable identifier for a market. Globally Unique. See ontology.md for details Eg "NYCMAYOR_20251104.MAMDANI" The markets event is derived from it's symbol see [Symbol::event_code()]
taker_fee_ratesigned decimal string, 6 d.p.YesBase fee rate paid by takers. Decimal string, e.g. "0.0010" for 10 bps. See [pascal_types::math::taker_fee] for more details.
maker_rebate_sharesigned decimal string, 6 d.p.YesShare of taker fee rebated to makers. Decimal string, e.g. "0.50" for 50%. See [pascal_types::math::fee_share] for more details.
tick_size_mindecimal string, 6 d.p.YesMinimum tick size. The tick size for a given price px is: max(tick_size_min, 10^(floor(log10(px')) - tick_sig_figs + 1)) where px' = min(px, 1 - px) The intuition is that we want some amount of decimal precision available, but we don't want to count 0 prefixes. For example, 0.0025, 0.025 and 0.25 all have 2 digits of precision.
tick_sig_figsintegerYesNumber of significant figures in the tick size formula. Must be in [1, 6].

Order Books#

GET <read_base_url>/api/v1/books

Returns order books for multiple comma-delimited symbols.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/books?symbols=SIM_EVENT_1.MARKET_1%2CSIM_EVENT_1.MARKET_2'
json
{
  "status": "success",
  "data": {
    "books": {
      "SIM_EVENT_1.MARKET_1": {
        "asks": [
          [
            "0.560000",
            "12"
          ],
          [
            "0.570000",
            "20"
          ]
        ],
        "bids": [
          [
            "0.540000",
            "15"
          ],
          [
            "0.530000",
            "7"
          ]
        ],
        "spec": {
          "symbol": "SIM_EVENT_1.MARKET_1",
          "taker_fee_rate": "0.001000",
          "maker_rebate_share": "0.500000",
          "tick_size_min": "0.010000",
          "tick_sig_figs": 2
        }
      },
      "SIM_EVENT_1.MARKET_2": {
        "asks": [
          [
            "0.560000",
            "12"
          ],
          [
            "0.570000",
            "20"
          ]
        ],
        "bids": [
          [
            "0.540000",
            "15"
          ],
          [
            "0.530000",
            "7"
          ]
        ]
      }
    }
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
symbolscomma-separated array of stringYesSymbols.

JSON Response Payload

FieldTypeRequiredDescription
booksobject mapping string to OrderBookMsgYesBooks.

Each value in books is an order book object:

FieldTypeRequiredDescription
asksarray of tuple (decimal string, 6 d.p., integer string)YesAsks.
bidsarray of tuple (decimal string, 6 d.p., integer string)YesBids.
specMarketSpecNoSpec.

spec object:

FieldTypeRequiredDescription
symbolstringYesHuman-readable identifier for a market. Globally Unique. See ontology.md for details Eg "NYCMAYOR_20251104.MAMDANI" The markets event is derived from it's symbol see [Symbol::event_code()]
taker_fee_ratesigned decimal string, 6 d.p.YesBase fee rate paid by takers. Decimal string, e.g. "0.0010" for 10 bps. See [pascal_types::math::taker_fee] for more details.
maker_rebate_sharesigned decimal string, 6 d.p.YesShare of taker fee rebated to makers. Decimal string, e.g. "0.50" for 50%. See [pascal_types::math::fee_share] for more details.
tick_size_mindecimal string, 6 d.p.YesMinimum tick size. The tick size for a given price px is: max(tick_size_min, 10^(floor(log10(px')) - tick_sig_figs + 1)) where px' = min(px, 1 - px) The intuition is that we want some amount of decimal precision available, but we don't want to count 0 prefixes. For example, 0.0025, 0.025 and 0.25 all have 2 digits of precision.
tick_sig_figsintegerYesNumber of significant figures in the tick size formula. Must be in [1, 6].

Candles#

GET <read_base_url>/api/v1/candles

Returns OHLCV candles for one market and interval. Ranges are end-exclusive. If start_time_ms is omitted, count_back controls how many candles are returned before end_time_ms.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/candles?symbol=SIM_EVENT_1.MARKET_1&interval=1m&end_time_ms=1731536000000&count_back=2'
json
{
  "status": "success",
  "data": [
    {
      "time": "1731535960000",
      "open": "0.520000",
      "high": "0.570000",
      "low": "0.510000",
      "close": "0.550000",
      "volume": "120",
      "taker_buy_volume": "70",
      "taker_sell_volume": "50",
      "volume_notional": "66.000000",
      "taker_buy_volume_notional": "38.500000",
      "taker_sell_volume_notional": "27.500000",
      "trade_count": "8",
      "taker_buy_count": "5",
      "taker_sell_count": "3"
    }
  ],
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
symbolstringYesSymbol.
intervalstringYesInterval.
end_time_msintegerYesEnd time ms.
start_time_msintegerNoStart time ms.
count_backintegerNoCount back.

JSON Response Payload

Returns a JSON array of candle objects. Every element in the array is a JSON object:

FieldTypeRequiredDescription
timeinteger stringYesTime.
opendecimal string, 6 d.p.YesOpen.
highdecimal string, 6 d.p.YesHigh.
lowdecimal string, 6 d.p.YesLow.
closedecimal string, 6 d.p.YesClose.
volumeinteger stringYesVolume.
taker_buy_volumeinteger stringYesTaker buy volume.
taker_sell_volumeinteger stringYesTaker sell volume.
volume_notionaldecimal string, 6 d.p.YesVolume notional.
taker_buy_volume_notionaldecimal string, 6 d.p.YesTaker buy volume notional.
taker_sell_volume_notionaldecimal string, 6 d.p.YesTaker sell volume notional.
trade_countinteger stringYesTrade count.
taker_buy_countinteger stringYesTaker buy count.
taker_sell_countinteger stringYesTaker sell count.

Public Trades#

GET <read_base_url>/api/v1/trades

Returns public trade history for one or more markets.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/trades?symbols=SIM_EVENT_1.MARKET_1&before_cursor=&limit=50'
json
{
  "status": "success",
  "data": {
    "items": [
      {
        "trade_id": "555001",
        "trade_ts_ms": "1731536000050",
        "taker_side": "BID",
        "size": "3",
        "price": "0.550000",
        "maker": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
        "taker": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1",
        "cursor": "00000000000000067891:0000000000"
      }
    ],
    "next_cursor": "00000000000000067890:0000000000",
    "historical_context": {
      "as_of_round": "12345",
      "as_of_esm_seq": "67891"
    }
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
symbolscomma-separated array of stringNoSymbols.
before_cursorfixed-width cursor stringNoBefore cursor.
limitintegerNoLimit.

JSON Response Payload

Returns a paginated JSON object:

FieldTypeRequiredDescription
itemsarray of PublicTradeMsgYesItems.
next_cursorfixed-width cursor stringNoNext cursor.
historical_contextHistoricalReadApiQueryContextYesHistorical context.

Every element in items is a JSON object:

FieldTypeRequiredDescription
trade_idinteger stringYesTrade id.
trade_ts_msinteger stringYesTrade ts ms.
taker_sideSideYesTaker side.
sizeinteger stringYesSize.
pricedecimal string, 6 d.p.YesPrice.
makerbase58 stringYesMaker.
takerbase58 stringYesTaker.
cursorfixed-width cursor stringYesCursor token for keyset pagination. For journaler-backed history and live trade streams, the first cursor component is esm_seq. The second component is an intra-effect tie-break index, which is always 0 for trades.

historical_context object:

FieldTypeRequiredDescription
as_of_roundinteger stringYesAs of round.
as_of_esm_seqinteger stringYesSerialized as a string for JS safety.

Account Data Endpoints#

Account Snapshot#

GET <read_base_url>/api/v1/account

Returns open orders, fills, positions, deposits, transfers, and collateral for one owner.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/account?user=GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB'
json
{
  "status": "success",
  "data": {
    "orders": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "side": "BID",
        "size_original": "10",
        "size_filled": "3",
        "notional_filled": "1.650000",
        "size_remaining": "7",
        "price": "0.550000",
        "status": "OPEN",
        "tif": "GTC",
        "type": "LIMIT",
        "post_only": false,
        "reduce_only": false,
        "expires_ts_ms": "0",
        "client_order_id": "42",
        "id": "987654321",
        "place_ts_ms": "1731536000050",
        "place_round": "12345",
        "update_ts_ms": "1731536000050",
        "update_round": "12345"
      }
    ],
    "fills": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "client_order_id": "42",
        "order_id": "987654321",
        "trade_id": "555001",
        "trade_ts_ms": "1731536000050",
        "cursor": "00000000000000067891:0000000000",
        "round": "12345",
        "side": "BID",
        "liquidity": "TAKER",
        "fill_size": "3",
        "fill_price": "0.550000",
        "fee_usd": "-0.020000",
        "collateral_change_usd": "-1.650000",
        "position_size_prev": "0",
        "realized_pnl_usd": "0.000000"
      }
    ],
    "positions": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "size": "7",
        "mark_price": "0.550000",
        "average_entry_price": "0.520000",
        "remaining_entry_notional_usd": "3.640000",
        "realized_pnl_usd": "0.000000",
        "open_size": "10",
        "open_notional": "5.200000",
        "close_size": "3",
        "close_notional": "1.650000",
        "cumulative_fees_paid": "-0.020000",
        "open_ts_ms": "1731535900000",
        "open_round": "12340",
        "update_ts_ms": "1731536000050",
        "update_round": "12345"
      }
    ],
    "resolutions": [],
    "inflight_deposits": [
      {
        "deposit_seq": "9",
        "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
        "amount": "100.000000",
        "status": "FINALIZED"
      }
    ],
    "transfers": [
      {
        "collateral_change": "100.000000",
        "type": "DEPOSIT",
        "time_ms": "1731535900000",
        "cursor": "00000000000000067880:0000000000"
      }
    ],
    "collateral_usd": "100.000000"
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
userstringYesUser.

JSON Response Payload

FieldTypeRequiredDescription
ordersarray of OrderMsgYesOrders.
fillsarray of FillMsgYesFills.
positionsarray of PositionMsgYesPositions.
resolutionsarray of PositionResolutionMsgYesResolutions.
inflight_depositsarray of DepositMsgYesInflight deposits.
transfersarray of TransferMsgYesTransfers.
collateral_usddecimal string, 6 d.p.NoCollateral usd.

Every element in orders is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
sideSideYesSide.
size_originalinteger stringYesSize original.
size_filledinteger stringYesSize filled.
notional_filleddecimal string, 6 d.p.YesCumulative notional fill value: sum of fill_price * fill_size for all fills. Divide by size_filled to get the average fill price.
size_remaininginteger stringYesSize remaining.
pricedecimal string, 6 d.p.YesPrice.
statusOrderStatusYesStatus.
tifTimeInForceYesTif.
typeOrderTypeYesType.
post_onlybooleanYesPost only.
reduce_onlybooleanYesReduce only.
expires_ts_msinteger stringYesExpires ts ms.
client_order_idinteger stringYesClient order id.
idinteger stringYesId.
place_ts_msinteger stringYesPlace ts ms.
place_roundinteger stringYesPlace round.
update_ts_msinteger stringYesUpdate ts ms.
update_roundinteger stringYesUpdate round.
builder_keybase58 stringNoBuilder key.
builder_fee_ratesigned decimal string, 6 d.p.NoBuilder fee rate.

Every element in fills is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
client_order_idinteger stringYesClient order id.
order_idinteger stringYesOrder id.
trade_idinteger stringYesTrade id.
trade_ts_msinteger stringYesTrade ts ms.
cursorfixed-width cursor stringYesCursor.
roundinteger stringYesRound.
sideSideYesSide.
liquidityLiquidityYesLiquidity.
fill_sizeinteger stringYesFill size.
fill_pricedecimal string, 6 d.p.YesFill price.
fee_usdsigned decimal string, 6 d.p.YesFee usd.
collateral_change_usdsigned decimal string, 6 d.p.YesCollateral change usd.
builder_keybase58 stringNoBuilder key.
builder_fee_usdsigned decimal string, 6 d.p.NoBuilder fee usd.
position_size_prevsigned integer stringYesPosition size prev.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized pnl usd.

Every element in positions is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
sizesigned integer stringYesSigned position size. Positive for long, negative for short.
mark_pricedecimal string, 6 d.p.YesMedian of whichever of (best bid, best ask, last trade) are available.
average_entry_pricedecimal string, 6 d.p.NoDisplay value for UI: average entry price of the remaining open position. Do not use for PnL accounting; use remaining_entry_notional_usd. None means there is no remaining open position.
remaining_entry_notional_usddecimal string, 6 d.p.YesTotal entry notional still assigned to the current open position. This is the entry notional of the remaining position after accounting for partial closes. For example, after opening 10 contracts and closing 4, this is the entry notional still assigned to the remaining 6 contracts. Use this with the latest mark price and size to compute exact unrealized PnL. average_entry_price is derived from this value for display.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized PnL accumulated in the current position lifecycle, excluding fees.
open_sizeinteger stringYesCumulative size of opening trades since last zero crossing.
open_notionaldecimal string, 6 d.p.YesCumulative notional of opening trades (sum of price * size for openings)
close_sizeinteger stringYesCumulative size of closing trades since last zero crossing.
close_notionaldecimal string, 6 d.p.YesCumulative notional of closing trades (sum of price * size for closings)
cumulative_fees_paidsigned decimal string, 6 d.p.YesCumulative fees paid on the position.
open_ts_msinteger stringYesWhen this position was opened. Resets on zero crossing (direction flip).
open_roundinteger stringYesOpen round.
update_ts_msinteger stringYesWhen this position last changed. Advances on every fill and resolution.
update_roundinteger stringYesUpdate round.

Every element in resolutions is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
resolutiondecimal string, 6 d.p.YesResolution.
sizesigned integer stringYesSize.
collateral_change_usddecimal string, 6 d.p.YesCollateral change usd.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized pnl usd.
time_msinteger stringYesTime ms.
roundinteger stringYesRound.

Every element in inflight_deposits is a JSON object:

FieldTypeRequiredDescription
deposit_seqinteger stringYesDeposit seq.
ownerbase58 stringYesOwner.
amountdecimal string, 6 d.p.YesAmount.
statusDepositStatusYesStatus.

Every element in transfers is a JSON object:

FieldTypeRequiredDescription
collateral_changesigned decimal string, 6 d.p.YesCollateral change.
typeTransferTypeYesType.
time_msinteger stringYesTime ms.
cursorfixed-width cursor stringYesCursor.

Trading Keys#

GET <read_base_url>/api/v1/api-keys

Returns active trading keys for one owner.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/api-keys?owner=GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB'
json
{
  "status": "success",
  "data": [
    {
      "trading_key": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1",
      "name": "api-doc-key",
      "expiration_ts_ms": "1732140800000"
    }
  ],
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
ownerbase58 stringYesOwner.

JSON Response Payload

Returns a JSON array of trading key objects. Every element in the array is a JSON object:

FieldTypeRequiredDescription
trading_keybase58 stringYesTrading key.
namestringYesName.
expiration_ts_msinteger stringYesExpiration ts ms.

Deposit Address#

GET <read_base_url>/api/v1/deposit-address

Returns the wallet-facing deposit address for one owner.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/deposit-address?owner=GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB'
json
{
  "status": "success",
  "data": {
    "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
    "deposit_address": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
    "registered": true
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
ownerbase58 stringYesOwner.

JSON Response Payload

FieldTypeRequiredDescription
ownerbase58 stringYesOwner.
deposit_addressbase58 stringYesWallet-facing deposit address for manual sends. This is the deposit PDA, not the derived token ATA that backend services watch and credit.
registeredbooleanYesRegistered.

Withdrawals#

GET <read_base_url>/api/v1/withdrawal

Returns in-flight withdrawals for one owner.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/withdrawal?owner=GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB'
json
{
  "status": "success",
  "data": [
    {
      "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "correlation_id": "170000000000000123",
      "amount": "25.000000",
      "destination_authority": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "destination_token_account": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "status": "RUNNING_PRE_CHECK",
      "deadline_ts_ms": "1731536060000"
    }
  ],
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
ownerbase58 stringYesOwner.

JSON Response Payload

Returns a JSON array of withdrawal status objects. Every element in the array is a JSON object:

FieldTypeRequiredDescription
ownerbase58 stringYesOwner.
correlation_idinteger stringYesCorrelation id.
amountdecimal string, 6 d.p.YesAmount.
destination_authoritybase58 stringYesDestination authority.
destination_token_accountbase58 stringYesDestination token account.
statusWithdrawalStatusYesStatus.
deadline_ts_msinteger stringNoDeadline ts ms.

User Fills#

GET <read_base_url>/api/v1/user-fills

Returns authenticated fill history for one owner, optionally filtered by symbols.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/user-fills?user=GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB&symbols=SIM_EVENT_1.MARKET_1&before_cursor=&limit=50'
json
{
  "status": "success",
  "data": {
    "items": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "client_order_id": "42",
        "order_id": "987654321",
        "trade_id": "555001",
        "trade_ts_ms": "1731536000050",
        "cursor": "00000000000000067891:0000000000",
        "round": "12345",
        "side": "BID",
        "liquidity": "TAKER",
        "fill_size": "3",
        "fill_price": "0.550000",
        "fee_usd": "-0.020000",
        "collateral_change_usd": "-1.650000",
        "position_size_prev": "0",
        "realized_pnl_usd": "0.000000"
      }
    ],
    "historical_context": {
      "as_of_round": "12345",
      "as_of_esm_seq": "67891"
    }
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
userstringNoUser.
symbolscomma-separated array of stringNoSymbols.
before_cursorfixed-width cursor stringNoBefore cursor.
limitintegerNoLimit.

JSON Response Payload

Returns a paginated JSON object:

FieldTypeRequiredDescription
itemsarray of FillMsgYesItems.
next_cursorfixed-width cursor stringNoNext cursor.
historical_contextHistoricalReadApiQueryContextYesHistorical context.

Every element in items is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
client_order_idinteger stringYesClient order id.
order_idinteger stringYesOrder id.
trade_idinteger stringYesTrade id.
trade_ts_msinteger stringYesTrade ts ms.
cursorfixed-width cursor stringYesCursor.
roundinteger stringYesRound.
sideSideYesSide.
liquidityLiquidityYesLiquidity.
fill_sizeinteger stringYesFill size.
fill_pricedecimal string, 6 d.p.YesFill price.
fee_usdsigned decimal string, 6 d.p.YesFee usd.
collateral_change_usdsigned decimal string, 6 d.p.YesCollateral change usd.
builder_keybase58 stringNoBuilder key.
builder_fee_usdsigned decimal string, 6 d.p.NoBuilder fee usd.
position_size_prevsigned integer stringYesPosition size prev.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized pnl usd.

historical_context object:

FieldTypeRequiredDescription
as_of_roundinteger stringYesAs of round.
as_of_esm_seqinteger stringYesSerialized as a string for JS safety.

User Transfers#

GET <read_base_url>/api/v1/user-transfers

Returns deposit and withdrawal transfer history for one owner.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/user-transfers?user=GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB&before_cursor=&limit=50'
json
{
  "status": "success",
  "data": {
    "items": [
      {
        "collateral_change": "100.000000",
        "type": "DEPOSIT",
        "time_ms": "1731535900000",
        "cursor": "00000000000000067880:0000000000"
      }
    ],
    "historical_context": {
      "as_of_round": "12345",
      "as_of_esm_seq": "67891"
    }
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
userbase58 stringYesUser.
before_cursorfixed-width cursor stringNoBefore cursor.
limitintegerNoLimit.

JSON Response Payload

Returns a paginated JSON object:

FieldTypeRequiredDescription
itemsarray of TransferMsgYesItems.
next_cursorfixed-width cursor stringNoNext cursor.
historical_contextHistoricalReadApiQueryContextYesHistorical context.

Every element in items is a JSON object:

FieldTypeRequiredDescription
collateral_changesigned decimal string, 6 d.p.YesCollateral change.
typeTransferTypeYesType.
time_msinteger stringYesTime ms.
cursorfixed-width cursor stringYesCursor.

historical_context object:

FieldTypeRequiredDescription
as_of_roundinteger stringYesAs of round.
as_of_esm_seqinteger stringYesSerialized as a string for JS safety.

User Position Resolutions#

GET <read_base_url>/api/v1/user-position-resolutions

Returns historical position-resolution payouts for one owner.

Examples
bash
curl 'https://data.canary.pascal.trade/api/v1/user-position-resolutions?user=GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB&before_cursor=&limit=50'
json
{
  "status": "success",
  "data": {
    "items": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "resolution": "1.000000",
        "size": "7",
        "collateral_change_usd": "7.000000",
        "realized_pnl_usd": "3.360000",
        "time_ms": "1731536000050",
        "round": "12345"
      }
    ],
    "historical_context": {
      "as_of_round": "12345",
      "as_of_esm_seq": "67891"
    }
  },
  "round": "12345",
  "exchange_time_ms": "1731536000050"
}

Query Parameters

FieldTypeRequiredDescription
userbase58 stringYesUser.
before_cursorfixed-width cursor stringNoBefore cursor.
limitintegerNoLimit.

JSON Response Payload

Returns a paginated JSON object:

FieldTypeRequiredDescription
itemsarray of PositionResolutionMsgYesItems.
next_cursorfixed-width cursor stringNoNext cursor.
historical_contextHistoricalReadApiQueryContextYesHistorical context.

Every element in items is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
resolutiondecimal string, 6 d.p.YesResolution.
sizesigned integer stringYesSize.
collateral_change_usddecimal string, 6 d.p.YesCollateral change usd.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized pnl usd.
time_msinteger stringYesTime ms.
roundinteger stringYesRound.

historical_context object:

FieldTypeRequiredDescription
as_of_roundinteger stringYesAs of round.
as_of_esm_seqinteger stringYesSerialized as a string for JS safety.

WebSocket API#

GET <ws_base_url> upgrades to a WebSocket connection. Clients send JSON text frames.

Client Messages#

Subscribe

Examples
json
{
  "type": "subscribe",
  "channels": [
    {
      "channel": "book",
      "symbol": "SIM_EVENT_1.MARKET_1"
    },
    {
      "channel": "trades",
      "symbol": "SIM_EVENT_1.MARKET_1"
    }
  ]
}
json
{
  "type": "unsubscribe",
  "channels": [
    {
      "channel": "book",
      "symbol": "SIM_EVENT_1.MARKET_1"
    }
  ]
}
json
{
  "type": "ping"
}
FieldTypeRequiredDescription
typestring literal "subscribe"YesRequest discriminator.
channelsarray of WsChannelYesChannels.

Unsubscribe

FieldTypeRequiredDescription
typestring literal "unsubscribe"YesRequest discriminator.
channelsarray of WsChannelYesChannels.

Ping

FieldTypeRequiredDescription
typestring literal "ping"YesRequest discriminator.

The server responds to ping with the literal JSON text frame {"type":"pong"}.

Channel descriptors

ValuePayloadDescription
"book"symbol: stringBook.
"trades"symbol: stringTrades.
"account"user: base58 stringAccount.
"candles"symbol: string<br>interval: CandleIntervalCandles.

Server Messages#

For each subscribed channel, the server emits a snapshot message followed by update messages whenever the channel state changes. Error messages flatten the channel descriptor with type: "error" and error fields.

Examples
json
{
  "channel": "book",
  "symbol": "SIM_EVENT_1.MARKET_1",
  "type": "error",
  "code": "market_not_found",
  "details": {
    "symbol": "SIM_EVENT_1.MARKET_1"
  }
}

Book Channel#

Order book snapshots and updates for one market.

JSON Message Payload

Examples
json
{
  "channel": "book",
  "symbol": "SIM_EVENT_1.MARKET_1",
  "data": {
    "asks": [
      [
        "0.560000",
        "12"
      ],
      [
        "0.570000",
        "20"
      ]
    ],
    "bids": [
      [
        "0.540000",
        "15"
      ],
      [
        "0.530000",
        "7"
      ]
    ],
    "spec": {
      "symbol": "SIM_EVENT_1.MARKET_1",
      "taker_fee_rate": "0.001000",
      "maker_rebate_share": "0.500000",
      "tick_size_min": "0.010000",
      "tick_sig_figs": 2
    }
  },
  "type": "snapshot",
  "round": "12346",
  "exchange_time_ms": "1731536000100"
}
json
{
  "channel": "book",
  "symbol": "SIM_EVENT_1.MARKET_1",
  "data": {
    "asks": [
      [
        "0.570000",
        "0"
      ]
    ],
    "bids": [
      [
        "0.540000",
        "15"
      ]
    ]
  },
  "type": "update",
  "round": "12346",
  "exchange_time_ms": "1731536000100"
}
FieldTypeRequiredDescription
asksarray of tuple (decimal string, 6 d.p., integer string)YesAsks.
bidsarray of tuple (decimal string, 6 d.p., integer string)YesBids.
specMarketSpecNoSpec.

spec object:

FieldTypeRequiredDescription
symbolstringYesHuman-readable identifier for a market. Globally Unique. See ontology.md for details Eg "NYCMAYOR_20251104.MAMDANI" The markets event is derived from it's symbol see [Symbol::event_code()]
taker_fee_ratesigned decimal string, 6 d.p.YesBase fee rate paid by takers. Decimal string, e.g. "0.0010" for 10 bps. See [pascal_types::math::taker_fee] for more details.
maker_rebate_sharesigned decimal string, 6 d.p.YesShare of taker fee rebated to makers. Decimal string, e.g. "0.50" for 50%. See [pascal_types::math::fee_share] for more details.
tick_size_mindecimal string, 6 d.p.YesMinimum tick size. The tick size for a given price px is: max(tick_size_min, 10^(floor(log10(px')) - tick_sig_figs + 1)) where px' = min(px, 1 - px) The intuition is that we want some amount of decimal precision available, but we don't want to count 0 prefixes. For example, 0.0025, 0.025 and 0.25 all have 2 digits of precision.
tick_sig_figsintegerYesNumber of significant figures in the tick size formula. Must be in [1, 6].

Channel Descriptor

FieldTypeRequiredDescription
channelstring literal "book"YesChannel discriminator.
symbolstringYesSymbol.

Trades Channel#

Public trades for one market.

JSON Message Payload

Examples
json
{
  "channel": "trades",
  "symbol": "SIM_EVENT_1.MARKET_1",
  "data": [
    {
      "trade_id": "555001",
      "trade_ts_ms": "1731536000050",
      "taker_side": "BID",
      "size": "3",
      "price": "0.550000",
      "maker": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
      "taker": "2KW2XRd9kwqet15Aha2oK3tYvd3nWbTFH1MBiRAv1BE1",
      "cursor": "00000000000000067891:0000000000"
    }
  ],
  "type": "update",
  "round": "12346",
  "exchange_time_ms": "1731536000100"
}

data is a JSON array of public trade objects. Every element in the array is a JSON object:

FieldTypeRequiredDescription
trade_idinteger stringYesTrade id.
trade_ts_msinteger stringYesTrade ts ms.
taker_sideSideYesTaker side.
sizeinteger stringYesSize.
pricedecimal string, 6 d.p.YesPrice.
makerbase58 stringYesMaker.
takerbase58 stringYesTaker.
cursorfixed-width cursor stringYesCursor token for keyset pagination. For journaler-backed history and live trade streams, the first cursor component is esm_seq. The second component is an intra-effect tie-break index, which is always 0 for trades.

Channel Descriptor

FieldTypeRequiredDescription
channelstring literal "trades"YesChannel discriminator.
symbolstringYesSymbol.

Candles Channel#

Current in-progress candle for one market and interval.

JSON Message Payload

Examples
json
{
  "channel": "candles",
  "symbol": "SIM_EVENT_1.MARKET_1",
  "interval": "1m",
  "data": [
    {
      "time": "1731535960000",
      "open": "0.520000",
      "high": "0.570000",
      "low": "0.510000",
      "close": "0.550000",
      "volume": "120",
      "taker_buy_volume": "70",
      "taker_sell_volume": "50",
      "volume_notional": "66.000000",
      "taker_buy_volume_notional": "38.500000",
      "taker_sell_volume_notional": "27.500000",
      "trade_count": "8",
      "taker_buy_count": "5",
      "taker_sell_count": "3"
    }
  ],
  "type": "update",
  "round": "12346",
  "exchange_time_ms": "1731536000100"
}

data is a JSON array of candle objects. Every element in the array is a JSON object:

FieldTypeRequiredDescription
timeinteger stringYesTime.
opendecimal string, 6 d.p.YesOpen.
highdecimal string, 6 d.p.YesHigh.
lowdecimal string, 6 d.p.YesLow.
closedecimal string, 6 d.p.YesClose.
volumeinteger stringYesVolume.
taker_buy_volumeinteger stringYesTaker buy volume.
taker_sell_volumeinteger stringYesTaker sell volume.
volume_notionaldecimal string, 6 d.p.YesVolume notional.
taker_buy_volume_notionaldecimal string, 6 d.p.YesTaker buy volume notional.
taker_sell_volume_notionaldecimal string, 6 d.p.YesTaker sell volume notional.
trade_countinteger stringYesTrade count.
taker_buy_countinteger stringYesTaker buy count.
taker_sell_countinteger stringYesTaker sell count.

Channel Descriptor

FieldTypeRequiredDescription
channelstring literal "candles"YesChannel discriminator.
symbolstringYesSymbol.
intervalCandleIntervalYesInterval.

Account Channel#

Live account updates for one owner.

JSON Message Payload

Examples
json
{
  "channel": "account",
  "user": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
  "data": {
    "orders": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "side": "BID",
        "size_original": "10",
        "size_filled": "3",
        "notional_filled": "1.650000",
        "size_remaining": "7",
        "price": "0.550000",
        "status": "OPEN",
        "tif": "GTC",
        "type": "LIMIT",
        "post_only": false,
        "reduce_only": false,
        "expires_ts_ms": "0",
        "client_order_id": "42",
        "id": "987654321",
        "place_ts_ms": "1731536000050",
        "place_round": "12345",
        "update_ts_ms": "1731536000050",
        "update_round": "12345"
      }
    ],
    "fills": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "client_order_id": "42",
        "order_id": "987654321",
        "trade_id": "555001",
        "trade_ts_ms": "1731536000050",
        "cursor": "00000000000000067891:0000000000",
        "round": "12345",
        "side": "BID",
        "liquidity": "TAKER",
        "fill_size": "3",
        "fill_price": "0.550000",
        "fee_usd": "-0.020000",
        "collateral_change_usd": "-1.650000",
        "position_size_prev": "0",
        "realized_pnl_usd": "0.000000"
      }
    ],
    "positions": [
      {
        "symbol": "SIM_EVENT_1.MARKET_1",
        "size": "7",
        "mark_price": "0.550000",
        "average_entry_price": "0.520000",
        "remaining_entry_notional_usd": "3.640000",
        "realized_pnl_usd": "0.000000",
        "open_size": "10",
        "open_notional": "5.200000",
        "close_size": "3",
        "close_notional": "1.650000",
        "cumulative_fees_paid": "-0.020000",
        "open_ts_ms": "1731535900000",
        "open_round": "12340",
        "update_ts_ms": "1731536000050",
        "update_round": "12345"
      }
    ],
    "resolutions": [],
    "inflight_deposits": [
      {
        "deposit_seq": "9",
        "owner": "GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB",
        "amount": "100.000000",
        "status": "FINALIZED"
      }
    ],
    "transfers": [
      {
        "collateral_change": "100.000000",
        "type": "DEPOSIT",
        "time_ms": "1731535900000",
        "cursor": "00000000000000067880:0000000000"
      }
    ],
    "collateral_usd": "100.000000"
  },
  "type": "update",
  "round": "12346",
  "exchange_time_ms": "1731536000100"
}
FieldTypeRequiredDescription
ordersarray of OrderMsgYesOrders.
fillsarray of FillMsgYesFills.
positionsarray of PositionMsgYesPositions.
resolutionsarray of PositionResolutionMsgYesResolutions.
inflight_depositsarray of DepositMsgYesInflight deposits.
transfersarray of TransferMsgYesTransfers.
collateral_usddecimal string, 6 d.p.NoCollateral usd.

Every element in orders is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
sideSideYesSide.
size_originalinteger stringYesSize original.
size_filledinteger stringYesSize filled.
notional_filleddecimal string, 6 d.p.YesCumulative notional fill value: sum of fill_price * fill_size for all fills. Divide by size_filled to get the average fill price.
size_remaininginteger stringYesSize remaining.
pricedecimal string, 6 d.p.YesPrice.
statusOrderStatusYesStatus.
tifTimeInForceYesTif.
typeOrderTypeYesType.
post_onlybooleanYesPost only.
reduce_onlybooleanYesReduce only.
expires_ts_msinteger stringYesExpires ts ms.
client_order_idinteger stringYesClient order id.
idinteger stringYesId.
place_ts_msinteger stringYesPlace ts ms.
place_roundinteger stringYesPlace round.
update_ts_msinteger stringYesUpdate ts ms.
update_roundinteger stringYesUpdate round.
builder_keybase58 stringNoBuilder key.
builder_fee_ratesigned decimal string, 6 d.p.NoBuilder fee rate.

Every element in fills is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
client_order_idinteger stringYesClient order id.
order_idinteger stringYesOrder id.
trade_idinteger stringYesTrade id.
trade_ts_msinteger stringYesTrade ts ms.
cursorfixed-width cursor stringYesCursor.
roundinteger stringYesRound.
sideSideYesSide.
liquidityLiquidityYesLiquidity.
fill_sizeinteger stringYesFill size.
fill_pricedecimal string, 6 d.p.YesFill price.
fee_usdsigned decimal string, 6 d.p.YesFee usd.
collateral_change_usdsigned decimal string, 6 d.p.YesCollateral change usd.
builder_keybase58 stringNoBuilder key.
builder_fee_usdsigned decimal string, 6 d.p.NoBuilder fee usd.
position_size_prevsigned integer stringYesPosition size prev.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized pnl usd.

Every element in positions is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
sizesigned integer stringYesSigned position size. Positive for long, negative for short.
mark_pricedecimal string, 6 d.p.YesMedian of whichever of (best bid, best ask, last trade) are available.
average_entry_pricedecimal string, 6 d.p.NoDisplay value for UI: average entry price of the remaining open position. Do not use for PnL accounting; use remaining_entry_notional_usd. None means there is no remaining open position.
remaining_entry_notional_usddecimal string, 6 d.p.YesTotal entry notional still assigned to the current open position. This is the entry notional of the remaining position after accounting for partial closes. For example, after opening 10 contracts and closing 4, this is the entry notional still assigned to the remaining 6 contracts. Use this with the latest mark price and size to compute exact unrealized PnL. average_entry_price is derived from this value for display.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized PnL accumulated in the current position lifecycle, excluding fees.
open_sizeinteger stringYesCumulative size of opening trades since last zero crossing.
open_notionaldecimal string, 6 d.p.YesCumulative notional of opening trades (sum of price * size for openings)
close_sizeinteger stringYesCumulative size of closing trades since last zero crossing.
close_notionaldecimal string, 6 d.p.YesCumulative notional of closing trades (sum of price * size for closings)
cumulative_fees_paidsigned decimal string, 6 d.p.YesCumulative fees paid on the position.
open_ts_msinteger stringYesWhen this position was opened. Resets on zero crossing (direction flip).
open_roundinteger stringYesOpen round.
update_ts_msinteger stringYesWhen this position last changed. Advances on every fill and resolution.
update_roundinteger stringYesUpdate round.

Every element in resolutions is a JSON object:

FieldTypeRequiredDescription
symbolstringYesSymbol.
resolutiondecimal string, 6 d.p.YesResolution.
sizesigned integer stringYesSize.
collateral_change_usddecimal string, 6 d.p.YesCollateral change usd.
realized_pnl_usdsigned decimal string, 6 d.p.YesRealized pnl usd.
time_msinteger stringYesTime ms.
roundinteger stringYesRound.

Every element in inflight_deposits is a JSON object:

FieldTypeRequiredDescription
deposit_seqinteger stringYesDeposit seq.
ownerbase58 stringYesOwner.
amountdecimal string, 6 d.p.YesAmount.
statusDepositStatusYesStatus.

Every element in transfers is a JSON object:

FieldTypeRequiredDescription
collateral_changesigned decimal string, 6 d.p.YesCollateral change.
typeTransferTypeYesType.
time_msinteger stringYesTime ms.
cursorfixed-width cursor stringYesCursor.

Channel Descriptor

FieldTypeRequiredDescription
channelstring literal "account"YesChannel discriminator.
userbase58 stringYesUser.

Pagination#

Paginated endpoints accept before_cursor and limit. Cursors are opaque strings of the form {esm_seq:020}:{event_index:010}. A request whose cursor references a sequence ahead of the current historical watermark is rejected with service_unavailable.

Paginated responses include items, optional next_cursor, and historical_context. The concrete item table is shown under each paginated endpoint.

Error Codes#

Read API errors use ErrorCode.

ValueDescription
"invalid_request"InvalidRequest.
"market_not_found"MarketNotFound.
"symbol_not_found"SymbolNotFound.
"user_not_found"UserNotFound.
"invalid_market_id"InvalidMarketId.
"invalid_interval"InvalidInterval.
"invalid_limit"InvalidLimit.
"internal_error"InternalError.
"service_unavailable"ServiceUnavailable.
"not_ready"NotReady.
"backpressure"Backpressure.

Write-side command errors are returned as stable string code values inside WriteErrorResponse.

FieldTypeRequiredDescription
codestringYesCode.
detailsJSON valueNoDetails.