Skip to content

Price WebSocket API

The Oracle server exposes a read-only WebSocket endpoint for live source ticks, aggregate price updates, and finalized source tick buckets.

Production WebSocket URL:

text
wss://api.coinpost.ai/oracle/ws/prices

Upstream endpoint path:

text
GET /ws/prices

Authentication

WebSocket upgrade authentication follows the Oracle server rule. When auth.enabled or cp_auth.enabled is true, send the API key as a Bearer token:

text
Authorization: Bearer <api_key>

Browser clients that cannot set custom WebSocket headers may pass the token on the WebSocket URL:

text
wss://api.coinpost.ai/oracle/ws/prices?token=<api_key>
wss://api.coinpost.ai/oracle/ws/prices?access_token=<api_key>

Query-token auth is accepted only for the price WebSocket endpoint.

REST operation pages document REST API authentication separately.

Client Messages

Client messages are JSON. Unknown fields are ignored.

Subscribe

json
{
  "type": "subscribe",
  "id": "btc-live",
  "symbols": ["BTC"],
  "channels": ["aggregate", "sources", "ticks"],
  "sources": ["bitbank", "binance_japan", "coinbase"],
  "include_snapshot": true
}

Fields:

  • id: optional subscription ID. The server echoes it as subscription_id.
  • symbols: required list of canonical symbols.
  • channels: optional list. Defaults to ["aggregate", "sources"].
  • sources: optional source filter. Omit or pass an empty list for all sources.
  • include_snapshot: optional boolean. When true, the server sends the latest state immediately.

Channels:

  • aggregate: receive snapshot aggregate data and aggregate_update messages.
  • sources: receive snapshot source data and source_update messages.
  • ticks: receive finalized tick messages.

Unsubscribe

json
{
  "type": "unsubscribe",
  "id": "btc-live"
}

If id is omitted, the default subscription is removed.

Ping

json
{
  "type": "ping",
  "ts": "2026-06-10T06:00:00Z"
}

Response:

json
{
  "type": "pong",
  "ts": "2026-06-10T06:00:00Z"
}

Server Messages

Snapshot

Sent after subscribe when include_snapshot is true. sources is a map of source name to the latest source tick.

json
{
  "type": "snapshot",
  "subscription_id": "btc-live",
  "symbol": "BTC",
  "asset_id": "d388491f-2ee0-337f-bad1-fd8f4444e076",
  "tick_interval": "1m0s",
  "aggregate": {
    "source": "aggregated",
    "selected_source": "bitbank",
    "selected_pair": "btc_jpy",
    "price_usd": "61363.4557105392479143",
    "price_jpy": "9839303",
    "tick_start": "2026-06-10T15:01:00+09:00",
    "tick_interval": "1m0s",
    "method": "source_vote",
    "vote_band_pct": "0.003",
    "vote_sources": ["bitbank", "bitflyer", "coinbase"],
    "rejected_sources": ["binance_japan"],
    "updated_at": "2026-06-10T15:01:24.347954002+09:00"
  },
  "sources": {
    "bitbank": {
      "symbol": "BTC",
      "asset_id": "d388491f-2ee0-337f-bad1-fd8f4444e076",
      "source": "bitbank",
      "pair": "btc_jpy",
      "tick_start": "2026-06-10T15:01:00+09:00",
      "tick_interval": "1m0s",
      "native_price": "9839303",
      "native_currency": "JPY",
      "price_jpy": "9839303",
      "price_usd": "61363.4557105392479143",
      "open": "9839303",
      "high": "9839303",
      "low": "9839303",
      "close": "9839303",
      "bid": "9837946",
      "ask": "9837947",
      "source_timestamp": "2026-06-10T15:01:10.046+09:00",
      "received_at": "2026-06-10T15:01:11.420015171+09:00",
      "transport": "websocket",
      "sample_count": 12
    }
  }
}

Source Update

Sent when channels includes sources. This is the lowest-latency public event for exchange source ticks.

json
{
  "type": "source_update",
  "subscription_id": "btc-live",
  "symbol": "BTC",
  "asset_id": "d388491f-2ee0-337f-bad1-fd8f4444e076",
  "source": "bitbank",
  "pair": "btc_jpy",
  "tick_start": "2026-06-10T15:01:00+09:00",
  "tick_interval": "1m0s",
  "native_price": "9839303",
  "native_currency": "JPY",
  "price_jpy": "9839303",
  "price_usd": "61363.4557105392479143",
  "open": "9839303",
  "high": "9839303",
  "low": "9839303",
  "close": "9839303",
  "bid": "9837946",
  "ask": "9837947",
  "source_timestamp": "2026-06-10T15:01:10.046+09:00",
  "received_at": "2026-06-10T15:01:11.420015171+09:00",
  "transport": "websocket",
  "sample_count": 12,
  "updated_at": "2026-06-10T15:01:11.421000000+09:00"
}

Field notes:

  • native_price: latest observed price in the source quote currency.
  • price_usd / price_jpy: normalized prices when conversion is available.
  • open, high, low, close: source tick bucket values for the current tick_start.
  • bid / ask: best bid and ask when the source ticker provides them.
  • sample_count: number of source messages folded into the current bucket.
  • source_timestamp: timestamp reported by the exchange or upstream source.
  • received_at: local receive time in the worker.

Bid and ask availability:

SourceBid/ask
bitbankYes
binance_japanYes
bitflyerYes
coinbaseYes
gmo_coinYes
coincheckNo, current collector uses trades
coingeckoNo, current collector uses simple price

These are ticker-level best bid and ask values. They are not a full order book.

Aggregate Update

Sent when channels includes aggregate. The worker recalculates the current aggregate after each source update.

json
{
  "type": "aggregate_update",
  "subscription_id": "btc-live",
  "symbol": "BTC",
  "asset_id": "d388491f-2ee0-337f-bad1-fd8f4444e076",
  "source": "bitbank",
  "tick_start": "2026-06-10T15:01:00+09:00",
  "tick_interval": "1m0s",
  "aggregate": {
    "source": "aggregated",
    "selected_source": "bitbank",
    "selected_pair": "btc_jpy",
    "price_usd": "61363.4557105392479143",
    "price_jpy": "9839303",
    "tick_start": "2026-06-10T15:01:00+09:00",
    "tick_interval": "1m0s",
    "method": "source_vote",
    "vote_band_pct": "0.003",
    "vote_sources": ["bitbank", "bitflyer", "coinbase"],
    "rejected_sources": ["binance_japan"],
    "updated_at": "2026-06-10T15:01:24.347954002+09:00"
  },
  "updated_at": "2026-06-10T15:01:24.347954002+09:00"
}

Tick

Sent when channels includes ticks and a tick bucket is finalized.

json
{
  "type": "tick",
  "subscription_id": "btc-live",
  "symbol": "BTC",
  "asset_id": "d388491f-2ee0-337f-bad1-fd8f4444e076",
  "tick_start": "2026-06-10T15:01:00+09:00",
  "tick_interval": "1m0s",
  "aggregate": {
    "source": "aggregated",
    "selected_source": "bitbank",
    "selected_pair": "btc_jpy",
    "price_usd": "61363.4557105392479143",
    "price_jpy": "9839303",
    "method": "source_vote",
    "vote_sources": ["bitbank", "bitflyer", "coinbase"],
    "rejected_sources": ["binance_japan"]
  },
  "sources": {
    "bitbank": {
      "pair": "btc_jpy",
      "native_price": "9839303",
      "native_currency": "JPY",
      "price_jpy": "9839303",
      "price_usd": "61363.4557105392479143",
      "open": "9839303",
      "high": "9839303",
      "low": "9839303",
      "close": "9839303",
      "bid": "9837946",
      "ask": "9837947",
      "transport": "websocket",
      "sample_count": 12
    }
  },
  "updated_at": "2026-06-10T15:02:02.000000000+09:00"
}

Example Client

js
const ws = new WebSocket("wss://api.coinpost.ai/oracle/ws/prices");

ws.addEventListener("open", () => {
  ws.send(JSON.stringify({
    type: "subscribe",
    id: "btc-live",
    symbols: ["BTC"],
    channels: ["aggregate", "sources"],
    include_snapshot: true
  }));
});

ws.addEventListener("message", (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === "source_update") {
    console.log(msg.source, msg.bid, msg.ask, msg.native_price);
  }
});

Operational Notes

  • GET /prices/sources?symbol=BTC filters stale source ticks. Through the production REST base URL, call https://api.coinpost.ai/oracle/prices/sources?symbol=BTC.
  • WebSocket source_update sends live updates as they arrive.
  • source_update includes current bucket OHLC values, not finalized historical candles.
  • Full order book depth is not part of this endpoint. Use exchange order book streams if full depth is required.